WIP: Everything shredded

Nathan Sobo created

Change summary

crates/context_menu/src/context_menu.rs         |   3 
crates/editor/src/display_map/block_map.rs      |   2 
crates/gpui/src/app.rs                          | 635 ++++++--------
crates/gpui/src/app/test_app_context.rs         |   4 
crates/gpui/src/app/window.rs                   | 796 ++++++------------
crates/gpui/src/elements.rs                     | 218 ++--
crates/gpui/src/elements/align.rs               |  35 
crates/gpui/src/elements/canvas.rs              |  23 
crates/gpui/src/elements/clipped.rs             |  37 
crates/gpui/src/elements/constrained_box.rs     |  55 
crates/gpui/src/elements/container.rs           |  36 
crates/gpui/src/elements/empty.rs               |  19 
crates/gpui/src/elements/expanded.rs            |  36 
crates/gpui/src/elements/flex.rs                |  77 +
crates/gpui/src/elements/hook.rs                |  39 
crates/gpui/src/elements/image.rs               |  21 
crates/gpui/src/elements/keystroke_label.rs     |  31 
crates/gpui/src/elements/label.rs               |  26 
crates/gpui/src/elements/list.rs                | 106 +-
crates/gpui/src/elements/mouse_event_handler.rs |  79 +
crates/gpui/src/elements/overlay.rs             |  33 
crates/gpui/src/elements/uniform_list.rs        |  46 
crates/gpui/src/text_layout.rs                  |   7 
crates/search/src/project_search.rs             |   4 
crates/theme_testbench/src/theme_testbench.rs   |   4 
crates/workspace/src/toolbar.rs                 |   2 
26 files changed, 1,085 insertions(+), 1,289 deletions(-)

Detailed changes

crates/context_menu/src/context_menu.rs 🔗

@@ -28,7 +28,8 @@ pub fn init(cx: &mut AppContext) {
     cx.add_action(ContextMenu::cancel);
 }
 
-type ContextMenuItemBuilder = Box<dyn Fn(&mut MouseState, &theme::ContextMenuItem) -> ElementBox>;
+type ContextMenuItemBuilder =
+    Box<dyn Fn(&mut MouseState, &theme::ContextMenuItem) -> ElementBox>;
 
 pub enum ContextMenuItemLabel {
     String(Cow<'static, str>),

crates/editor/src/display_map/block_map.rs 🔗

@@ -4,7 +4,7 @@ use super::{
 };
 use crate::{Anchor, ExcerptId, ExcerptRange, ToPoint as _};
 use collections::{Bound, HashMap, HashSet};
-use gpui::{fonts::HighlightStyle, ElementBox, RenderContext};
+use gpui::{fonts::HighlightStyle, RenderContext, ElementBox};
 use language::{BufferSnapshot, Chunk, Patch, Point};
 use parking_lot::Mutex;
 use std::{

crates/gpui/src/app.rs 🔗

@@ -45,15 +45,15 @@ use crate::{
     executor::{self, Task},
     keymap_matcher::{self, Binding, KeymapContext, KeymapMatcher, Keystroke, MatchResult},
     platform::{
-        self, Appearance, KeyDownEvent, KeyUpEvent, ModifiersChangedEvent, MouseButton,
+        self, Appearance, FontSystem, KeyDownEvent, KeyUpEvent, ModifiersChangedEvent, MouseButton,
         PathPromptOptions, Platform, PromptLevel, WindowBounds, WindowOptions,
     },
     util::post_inc,
     window::{Window, WindowContext},
-    AssetCache, AssetSource, ClipboardItem, FontCache, MouseRegionId, TextLayoutCache,
+    AssetCache, AssetSource, ClipboardItem, FontCache, MouseRegionId,
 };
 
-use self::ref_counts::RefCounts;
+use self::{ref_counts::RefCounts, window::RenderedView};
 
 pub trait Entity: 'static {
     type Event;
@@ -69,7 +69,7 @@ pub trait Entity: 'static {
 
 pub trait View: Entity + Sized {
     fn ui_name() -> &'static str;
-    fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox;
+    fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox<Self>;
     fn focus_in(&mut self, _: AnyViewHandle, _: &mut ViewContext<Self>) {}
     fn focus_out(&mut self, _: AnyViewHandle, _: &mut ViewContext<Self>) {}
     fn key_down(&mut self, _: &KeyDownEvent, _: &mut ViewContext<Self>) -> bool {
@@ -516,12 +516,13 @@ pub struct AppContext {
     element_states: HashMap<ElementStateId, Box<dyn Any>>,
     background: Arc<executor::Background>,
     ref_counts: Arc<Mutex<RefCounts>>,
-    font_cache: Arc<FontCache>,
-    platform: Arc<dyn Platform>,
 
     weak_self: Option<rc::Weak<RefCell<Self>>>,
+    platform: Arc<dyn Platform>,
     foreground_platform: Rc<dyn platform::ForegroundPlatform>,
-    assets: Arc<AssetCache>,
+    pub asset_cache: Arc<AssetCache>,
+    font_system: Arc<dyn FontSystem>,
+    pub font_cache: Arc<FontCache>,
     action_deserializers: HashMap<&'static str, (TypeId, DeserializeActionCallback)>,
     capture_actions: HashMap<TypeId, HashMap<TypeId, Vec<Box<ActionCallback>>>>,
     // Entity Types -> { Action Types -> Action Handlers }
@@ -577,12 +578,13 @@ impl AppContext {
             element_states: Default::default(),
             ref_counts: Arc::new(Mutex::new(ref_counts)),
             background,
-            font_cache,
-            platform,
 
             weak_self: None,
+            font_system: platform.fonts(),
+            platform,
             foreground_platform,
-            assets: Arc::new(AssetCache::new(asset_source)),
+            font_cache,
+            asset_cache: Arc::new(AssetCache::new(asset_source)),
             action_deserializers: Default::default(),
             capture_actions: Default::default(),
             actions: Default::default(),
@@ -727,7 +729,7 @@ impl AppContext {
                   window_id: usize,
                   view_id: usize| {
                 let action = action.as_any().downcast_ref().unwrap();
-                let mut cx = ViewContext::new(cx, window_id, view_id);
+                let mut cx = ViewContext::new(cx, view_id);
                 handler(
                     view.as_any_mut()
                         .downcast_mut()
@@ -805,36 +807,6 @@ impl AppContext {
         self.windows.keys().copied()
     }
 
-    pub fn window_is_active(&self, window_id: usize) -> bool {
-        self.windows
-            .get(&window_id)
-            .map_or(false, |window| window.is_active)
-    }
-
-    pub fn window_is_fullscreen(&self, window_id: usize) -> bool {
-        self.windows
-            .get(&window_id)
-            .map_or(false, |window| window.is_fullscreen)
-    }
-
-    pub fn root_view(&self, window_id: usize) -> Option<AnyViewHandle> {
-        self.windows
-            .get(&window_id)
-            .map(|window| window.root_view.clone())
-    }
-
-    pub fn root_view_id(&self, window_id: usize) -> Option<usize> {
-        self.windows
-            .get(&window_id)
-            .map(|window| window.root_view.id())
-    }
-
-    pub fn focused_view_id(&self, window_id: usize) -> Option<usize> {
-        self.windows
-            .get(&window_id)
-            .and_then(|window| window.focused_view_id)
-    }
-
     pub fn view_ui_name(&self, window_id: usize, view_id: usize) -> Option<&'static str> {
         Some(self.views.get(&(window_id, view_id))?.ui_name())
     }
@@ -886,57 +858,57 @@ impl AppContext {
         self.active_labeled_tasks.values().cloned()
     }
 
-    pub fn render_view(&mut self, params: RenderParams) -> Result<ElementBox> {
-        let window_id = params.window_id;
-        let view_id = params.view_id;
-        let mut view = self
-            .views
-            .remove(&(window_id, view_id))
-            .ok_or_else(|| anyhow!("view not found"))?;
-        let element = view.render(params, self);
-        self.views.insert((window_id, view_id), view);
-        Ok(element)
-    }
-
-    pub fn render_views(
-        &mut self,
-        window_id: usize,
-        titlebar_height: f32,
-        appearance: Appearance,
-    ) -> HashMap<usize, ElementBox> {
-        self.start_frame();
-        #[allow(clippy::needless_collect)]
-        let view_ids = self
-            .views
-            .keys()
-            .filter_map(|(win_id, view_id)| {
-                if *win_id == window_id {
-                    Some(*view_id)
-                } else {
-                    None
-                }
-            })
-            .collect::<Vec<_>>();
-
-        view_ids
-            .into_iter()
-            .map(|view_id| {
-                (
-                    view_id,
-                    self.render_view(RenderParams {
-                        window_id,
-                        view_id,
-                        titlebar_height,
-                        hovered_region_ids: Default::default(),
-                        clicked_region_ids: None,
-                        refreshing: false,
-                        appearance,
-                    })
-                    .unwrap(),
-                )
-            })
-            .collect()
-    }
+    // pub fn render_view(&mut self, params: RenderParams) -> Result<ElementBox<Self>> {
+    //     let window_id = params.window_id;
+    //     let view_id = params.view_id;
+    //     let mut view = self
+    //         .views
+    //         .remove(&(window_id, view_id))
+    //         .ok_or_else(|| anyhow!("view not found"))?;
+    //     let element = view.render(params, self);
+    //     self.views.insert((window_id, view_id), view);
+    //     Ok(element)
+    // }
+
+    // pub fn render_views(
+    //     &mut self,
+    //     window_id: usize,
+    //     titlebar_height: f32,
+    //     appearance: Appearance,
+    // ) -> HashMap<usize, ElementBox> {
+    //     self.start_frame();
+    //     #[allow(clippy::needless_collect)]
+    //     let view_ids = self
+    //         .views
+    //         .keys()
+    //         .filter_map(|(win_id, view_id)| {
+    //             if *win_id == window_id {
+    //                 Some(*view_id)
+    //             } else {
+    //                 None
+    //             }
+    //         })
+    //         .collect::<Vec<_>>();
+
+    //     view_ids
+    //         .into_iter()
+    //         .map(|view_id| {
+    //             (
+    //                 view_id,
+    //                 self.render_view(RenderParams {
+    //                     window_id,
+    //                     view_id,
+    //                     titlebar_height,
+    //                     hovered_region_ids: Default::default(),
+    //                     clicked_region_ids: None,
+    //                     refreshing: false,
+    //                     appearance,
+    //                 })
+    //                 .unwrap(),
+    //             )
+    //         })
+    //         .collect()
+    // }
 
     pub(crate) fn start_frame(&mut self) {
         self.frame_count += 1;
@@ -1464,73 +1436,6 @@ impl AppContext {
         self.keystroke_matcher.clear_bindings();
     }
 
-    pub fn dispatch_key_down(&mut self, window_id: usize, event: &KeyDownEvent) -> bool {
-        if let Some(focused_view_id) = self.focused_view_id(window_id) {
-            for view_id in self
-                .ancestors(window_id, focused_view_id)
-                .collect::<Vec<_>>()
-            {
-                if let Some(mut view) = self.views.remove(&(window_id, view_id)) {
-                    let handled = view.key_down(event, self, window_id, view_id);
-                    self.views.insert((window_id, view_id), view);
-                    if handled {
-                        return true;
-                    }
-                } else {
-                    log::error!("view {} does not exist", view_id)
-                }
-            }
-        }
-
-        false
-    }
-
-    pub fn dispatch_key_up(&mut self, window_id: usize, event: &KeyUpEvent) -> bool {
-        if let Some(focused_view_id) = self.focused_view_id(window_id) {
-            for view_id in self
-                .ancestors(window_id, focused_view_id)
-                .collect::<Vec<_>>()
-            {
-                if let Some(mut view) = self.views.remove(&(window_id, view_id)) {
-                    let handled = view.key_up(event, self, window_id, view_id);
-                    self.views.insert((window_id, view_id), view);
-                    if handled {
-                        return true;
-                    }
-                } else {
-                    log::error!("view {} does not exist", view_id)
-                }
-            }
-        }
-
-        false
-    }
-
-    pub fn dispatch_modifiers_changed(
-        &mut self,
-        window_id: usize,
-        event: &ModifiersChangedEvent,
-    ) -> bool {
-        if let Some(focused_view_id) = self.focused_view_id(window_id) {
-            for view_id in self
-                .ancestors(window_id, focused_view_id)
-                .collect::<Vec<_>>()
-            {
-                if let Some(mut view) = self.views.remove(&(window_id, view_id)) {
-                    let handled = view.modifiers_changed(event, self, window_id, view_id);
-                    self.views.insert((window_id, view_id), view);
-                    if handled {
-                        return true;
-                    }
-                } else {
-                    log::error!("view {} does not exist", view_id)
-                }
-            }
-        }
-
-        false
-    }
-
     pub fn default_global<T: 'static + Default>(&mut self) -> &T {
         let type_id = TypeId::of::<T>();
         self.update(|this| {
@@ -1748,17 +1653,8 @@ impl AppContext {
             window_id,
         }));
 
-        let mut window = Window::new(
-            window_id,
-            root_view,
-            platform_window,
-            self.font_cache.clone(),
-            TextLayoutCache::new(self.platform.fonts()),
-            self.assets.clone(),
-            self,
-        );
-
-        let scene = WindowContext::new(self, &mut window, window_id).build_scene(false);
+        let mut window = Window::new(window_id, root_view, platform_window, self);
+        let scene = WindowContext::new(self, &mut window, window_id).build_scene();
         window.platform_window.present_scene(scene);
         window
     }
@@ -1807,7 +1703,7 @@ impl AppContext {
             let view_id = post_inc(&mut this.next_entity_id);
             // Make sure we can tell child views about their parent
             this.parents.insert((window_id, view_id), parent_id);
-            let mut cx = ViewContext::new(this, window_id, view_id);
+            let mut cx = ViewContext::new(this, view_id);
             let handle = if let Some(view) = build_view(&mut cx) {
                 this.views.insert((window_id, view_id), Box::new(view));
                 if let Some(window) = this.windows.get_mut(&window_id) {
@@ -2108,7 +2004,7 @@ impl AppContext {
                 if let Some(mut invalidation) = cx.window.invalidation.take() {
                     let appearance = cx.window.platform_window.appearance();
                     cx.invalidate(&mut invalidation, appearance);
-                    let scene = cx.build_scene(false);
+                    let scene = cx.build_scene();
                     cx.window.platform_window.present_scene(scene);
                 }
             });
@@ -2181,7 +2077,8 @@ impl AppContext {
             self.update_window(window_id, |cx| {
                 let mut invalidation = cx.window.invalidation.take().unwrap_or_default();
                 cx.invalidate(&mut invalidation, cx.window.platform_window.appearance());
-                let scene = cx.build_scene(true);
+                cx.refreshing = true;
+                let scene = cx.build_scene();
                 cx.window.platform_window.present_scene(scene);
             });
         }
@@ -2275,78 +2172,76 @@ impl AppContext {
             return;
         }
 
-        self.update(|this| {
-            let window = this.windows.get_mut(&window_id)?;
-            window.is_active = active;
-
-            //Handle focus
-            let focused_id = window.focused_view_id?;
-            for view_id in this.ancestors(window_id, focused_id).collect::<Vec<_>>() {
-                if let Some(mut view) = this.views.remove(&(window_id, view_id)) {
-                    if active {
-                        view.focus_in(this, window_id, view_id, focused_id);
-                    } else {
-                        view.focus_out(this, window_id, view_id, focused_id);
-                    }
-                    this.views.insert((window_id, view_id), view);
+        self.update(|cx| {
+            cx.update_window(window_id, |cx| {
+                let focused_id = cx.window.focused_view_id?;
+                for view_id in cx.ancestors(window_id, focused_id).collect::<Vec<_>>() {
+                    cx.update_any_view(focused_id, |view, cx| {
+                        if active {
+                            view.focus_in(focused_id, cx, view_id);
+                        } else {
+                            view.focus_out(focused_id, cx, view_id);
+                        }
+                    });
                 }
-            }
+            });
 
-            let mut observations = this.window_activation_observations.clone();
-            observations.emit(window_id, this, |callback, this| callback(active, this));
+            let mut observations = cx.window_activation_observations.clone();
+            observations.emit(window_id, cx, |callback, this| callback(active, this));
 
             Some(())
         });
     }
 
     fn handle_focus_effect(&mut self, window_id: usize, focused_id: Option<usize>) {
-        if self
-            .windows
-            .get(&window_id)
-            .map(|w| w.focused_view_id)
-            .map_or(false, |cur_focused| cur_focused == focused_id)
-        {
-            return;
-        }
-
-        self.update(|this| {
-            let blurred_id = this.windows.get_mut(&window_id).and_then(|window| {
-                let blurred_id = window.focused_view_id;
-                window.focused_view_id = focused_id;
-                blurred_id
-            });
-
-            let blurred_parents = blurred_id
-                .map(|blurred_id| this.ancestors(window_id, blurred_id).collect::<Vec<_>>())
-                .unwrap_or_default();
-            let focused_parents = focused_id
-                .map(|focused_id| this.ancestors(window_id, focused_id).collect::<Vec<_>>())
-                .unwrap_or_default();
-
-            if let Some(blurred_id) = blurred_id {
-                for view_id in blurred_parents.iter().copied() {
-                    if let Some(mut view) = this.views.remove(&(window_id, view_id)) {
-                        view.focus_out(this, window_id, view_id, blurred_id);
-                        this.views.insert((window_id, view_id), view);
-                    }
-                }
-
-                let mut subscriptions = this.focus_observations.clone();
-                subscriptions.emit(blurred_id, this, |callback, this| callback(false, this));
-            }
-
-            if let Some(focused_id) = focused_id {
-                for view_id in focused_parents {
-                    if let Some(mut view) = this.views.remove(&(window_id, view_id)) {
-                        view.focus_in(this, window_id, view_id, focused_id);
-                        this.views.insert((window_id, view_id), view);
-                    }
-                }
-
-                let mut subscriptions = this.focus_observations.clone();
-                subscriptions.emit(focused_id, this, |callback, this| callback(true, this));
-            }
-        })
+        todo!()
+        // if self
+        //     .windows
+        //     .get(&window_id)
+        //     .map(|w| w.focused_view_id)
+        //     .map_or(false, |cur_focused| cur_focused == focused_id)
+        // {
+        //     return;
+        // }
+
+        // self.update(|this| {
+        //     let blurred_id = this.windows.get_mut(&window_id).and_then(|window| {
+        //         let blurred_id = window.focused_view_id;
+        //         window.focused_view_id = focused_id;
+        //         blurred_id
+        //     });
+
+        //     let blurred_parents = blurred_id
+        //         .map(|blurred_id| this.ancestors(window_id, blurred_id).collect::<Vec<_>>())
+        //         .unwrap_or_default();
+        //     let focused_parents = focused_id
+        //         .map(|focused_id| this.ancestors(window_id, focused_id).collect::<Vec<_>>())
+        //         .unwrap_or_default();
+
+        //     if let Some(blurred_id) = blurred_id {
+        //         for view_id in blurred_parents.iter().copied() {
+        //             if let Some(mut view) = this.views.remove(&(window_id, view_id)) {
+        //                 view.focus_out(this, window_id, view_id, blurred_id);
+        //                 this.views.insert((window_id, view_id), view);
+        //             }
+        //         }
+
+        //         let mut subscriptions = this.focus_observations.clone();
+        //         subscriptions.emit(blurred_id, this, |callback, this| callback(false, this));
+        //     }
+
+        //     if let Some(focused_id) = focused_id {
+        //         for view_id in focused_parents {
+        //             if let Some(mut view) = this.views.remove(&(window_id, view_id)) {
+        //                 view.focus_in(this, window_id, view_id, focused_id);
+        //                 this.views.insert((window_id, view_id), view);
+        //             }
+        //         }
+
+        //         let mut subscriptions = this.focus_observations.clone();
+        //         subscriptions.emit(focused_id, this, |callback, this| callback(true, this));
+        //     }
+        // })
     }
 
     fn handle_dispatch_action_from_effect(
@@ -2634,7 +2529,7 @@ impl UpdateView for AppContext {
                 .remove(&(handle.window_id, handle.view_id))
                 .expect("circular view update");
 
-            let mut cx = ViewContext::new(this, handle.window_id, handle.view_id);
+            let mut cx = ViewContext::new(this, handle.view_id);
             let result = update(
                 view.as_any_mut()
                     .downcast_mut()
@@ -2982,64 +2877,68 @@ pub trait AnyView {
         cx: &mut AppContext,
     ) -> Option<Pin<Box<dyn 'static + Future<Output = ()>>>>;
     fn ui_name(&self) -> &'static str;
-    fn render(&mut self, params: RenderParams, cx: &mut AppContext) -> ElementBox;
-    fn focus_in(
+    fn render<'a, 'b>(
+        &mut self,
+        params: RenderParams,
+        cx: &'b mut WindowContext<'a, 'b>,
+    ) -> Box<dyn RenderedView>;
+    fn focus_in<'a, 'b>(
         &mut self,
-        cx: &mut AppContext,
-        window_id: usize,
-        view_id: usize,
         focused_id: usize,
+        cx: &'b mut WindowContext<'a, 'b>,
+        view_id: usize,
     );
-    fn focus_out(
+    fn focus_out<'a, 'b>(
         &mut self,
-        cx: &mut AppContext,
-        window_id: usize,
-        view_id: usize,
         focused_id: usize,
+        cx: &'b mut WindowContext<'a, 'b>,
+        view_id: usize,
     );
-    fn key_down(
+    fn key_down<'a, 'b>(
         &mut self,
         event: &KeyDownEvent,
-        cx: &mut AppContext,
-        window_id: usize,
+        cx: &'b mut WindowContext<'a, 'b>,
         view_id: usize,
     ) -> bool;
-    fn key_up(
+    fn key_up<'a, 'b>(
         &mut self,
         event: &KeyUpEvent,
-        cx: &mut AppContext,
-        window_id: usize,
+        cx: &'b mut WindowContext<'a, 'b>,
         view_id: usize,
     ) -> bool;
-    fn modifiers_changed(
+    fn modifiers_changed<'a, 'b>(
         &mut self,
         event: &ModifiersChangedEvent,
-        cx: &mut AppContext,
-        window_id: usize,
+        cx: &'b mut WindowContext<'a, 'b>,
         view_id: usize,
     ) -> bool;
-    fn keymap_context(&self, cx: &AppContext) -> KeymapContext;
-    fn debug_json(&self, cx: &AppContext) -> serde_json::Value;
+    fn keymap_context<'a, 'b>(&self, cx: &'b mut WindowContext<'a, 'b>) -> KeymapContext;
+    fn debug_json<'a, 'b>(&self, cx: &'b WindowContext<'a, 'b>) -> serde_json::Value;
 
-    fn text_for_range(&self, range: Range<usize>, cx: &AppContext) -> Option<String>;
-    fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>>;
-    fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>>;
-    fn unmark_text(&mut self, cx: &mut AppContext, window_id: usize, view_id: usize);
-    fn replace_text_in_range(
+    fn text_for_range<'a, 'b>(
+        &self,
+        range: Range<usize>,
+        cx: &'b mut WindowContext<'a, 'b>,
+    ) -> Option<String>;
+    fn selected_text_range<'a, 'b>(
+        &self,
+        cx: &'b mut WindowContext<'a, 'b>,
+    ) -> Option<Range<usize>>;
+    fn marked_text_range<'a, 'b>(&self, cx: &'b mut WindowContext<'a, 'b>) -> Option<Range<usize>>;
+    fn unmark_text<'a, 'b>(&mut self, cx: &'b mut WindowContext<'a, 'b>, view_id: usize);
+    fn replace_text_in_range<'a, 'b>(
         &mut self,
         range: Option<Range<usize>>,
         text: &str,
-        cx: &mut AppContext,
-        window_id: usize,
+        cx: &'b mut WindowContext<'a, 'b>,
         view_id: usize,
     );
-    fn replace_and_mark_text_in_range(
+    fn replace_and_mark_text_in_range<'a, 'b>(
         &mut self,
         range: Option<Range<usize>>,
         new_text: &str,
         new_selected_range: Option<Range<usize>>,
-        cx: &mut AppContext,
-        window_id: usize,
+        cx: &'b mut WindowContext<'a, 'b>,
         view_id: usize,
     );
     fn any_handle(&self, window_id: usize, view_id: usize, cx: &AppContext) -> AnyViewHandle {
@@ -3079,134 +2978,145 @@ where
         T::ui_name()
     }
 
-    fn render(&mut self, params: RenderParams, cx: &mut AppContext) -> ElementBox {
+    fn render<'a, 'b>(
+        &mut self,
+        params: RenderParams,
+        cx: &mut WindowContext<'a, 'b>,
+    ) -> Box<dyn RenderedView> {
         View::render(self, &mut RenderContext::new(params, cx))
     }
 
-    fn focus_in(
+    fn focus_in<'a, 'b>(
         &mut self,
-        cx: &mut AppContext,
-        window_id: usize,
+        cx: &mut WindowContext<'a, 'b>,
         view_id: usize,
         focused_id: usize,
     ) {
-        let mut cx = ViewContext::new(cx, window_id, view_id);
+        let mut cx = ViewContext::new(cx, view_id);
         let focused_view_handle: AnyViewHandle = if view_id == focused_id {
             cx.handle().into_any()
         } else {
             let focused_type = cx
                 .views
-                .get(&(window_id, focused_id))
+                .get(&(cx.window_id, focused_id))
                 .unwrap()
                 .as_any()
                 .type_id();
-            AnyViewHandle::new(window_id, focused_id, focused_type, cx.ref_counts.clone())
+            AnyViewHandle::new(
+                cx.window_id,
+                focused_id,
+                focused_type,
+                cx.ref_counts.clone(),
+            )
         };
         View::focus_in(self, focused_view_handle, &mut cx);
     }
 
-    fn focus_out(
+    fn focus_out<'a, 'b>(
         &mut self,
-        cx: &mut AppContext,
-        window_id: usize,
+        cx: &mut WindowContext<'a, 'b>,
         view_id: usize,
         blurred_id: usize,
     ) {
-        let mut cx = ViewContext::new(cx, window_id, view_id);
+        let mut cx = ViewContext::new(cx, view_id);
         let blurred_view_handle: AnyViewHandle = if view_id == blurred_id {
             cx.handle().into_any()
         } else {
             let blurred_type = cx
                 .views
-                .get(&(window_id, blurred_id))
+                .get(&(cx.window_id, blurred_id))
                 .unwrap()
                 .as_any()
                 .type_id();
-            AnyViewHandle::new(window_id, blurred_id, blurred_type, cx.ref_counts.clone())
+            AnyViewHandle::new(
+                cx.window_id,
+                blurred_id,
+                blurred_type,
+                cx.ref_counts.clone(),
+            )
         };
         View::focus_out(self, blurred_view_handle, &mut cx);
     }
 
-    fn key_down(
+    fn key_down<'a, 'b>(
         &mut self,
         event: &KeyDownEvent,
-        cx: &mut AppContext,
-        window_id: usize,
+        cx: &mut WindowContext<'a, 'b>,
         view_id: usize,
     ) -> bool {
-        let mut cx = ViewContext::new(cx, window_id, view_id);
+        let mut cx = ViewContext::new(cx, view_id);
         View::key_down(self, event, &mut cx)
     }
 
-    fn key_up(
+    fn key_up<'a, 'b>(
         &mut self,
         event: &KeyUpEvent,
-        cx: &mut AppContext,
-        window_id: usize,
+        cx: &mut WindowContext<'a, 'b>,
         view_id: usize,
     ) -> bool {
-        let mut cx = ViewContext::new(cx, window_id, view_id);
+        let mut cx = ViewContext::new(cx, view_id);
         View::key_up(self, event, &mut cx)
     }
 
-    fn modifiers_changed(
+    fn modifiers_changed<'a, 'b>(
         &mut self,
         event: &ModifiersChangedEvent,
-        cx: &mut AppContext,
-        window_id: usize,
+        cx: &mut WindowContext<'a, 'b>,
         view_id: usize,
     ) -> bool {
-        let mut cx = ViewContext::new(cx, window_id, view_id);
+        let mut cx = ViewContext::new(cx, view_id);
         View::modifiers_changed(self, event, &mut cx)
     }
 
-    fn keymap_context(&self, cx: &AppContext) -> KeymapContext {
+    fn keymap_context<'a, 'b>(&self, cx: &mut WindowContext<'a, 'b>) -> KeymapContext {
         View::keymap_context(self, cx)
     }
 
-    fn debug_json(&self, cx: &AppContext) -> serde_json::Value {
+    fn debug_json<'a, 'b>(&self, cx: &mut WindowContext<'a, 'b>) -> serde_json::Value {
         View::debug_json(self, cx)
     }
 
-    fn text_for_range(&self, range: Range<usize>, cx: &AppContext) -> Option<String> {
+    fn text_for_range<'a, 'b>(
+        &self,
+        range: Range<usize>,
+        cx: &mut WindowContext<'a, 'b>,
+    ) -> Option<String> {
         View::text_for_range(self, range, cx)
     }
 
-    fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
+    fn selected_text_range<'a, 'b>(&self, cx: &mut WindowContext<'a, 'b>) -> Option<Range<usize>> {
         View::selected_text_range(self, cx)
     }
 
-    fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
+    fn marked_text_range<'a, 'b>(&self, cx: &mut WindowContext<'a, 'b>) -> Option<Range<usize>> {
         View::marked_text_range(self, cx)
     }
 
-    fn unmark_text(&mut self, cx: &mut AppContext, window_id: usize, view_id: usize) {
-        let mut cx = ViewContext::new(cx, window_id, view_id);
+    fn unmark_text<'a, 'b>(&mut self, cx: &mut WindowContext<'a, 'b>, view_id: usize) {
+        let mut cx = ViewContext::new(cx, view_id);
         View::unmark_text(self, &mut cx)
     }
 
-    fn replace_text_in_range(
+    fn replace_text_in_range<'a, 'b>(
         &mut self,
         range: Option<Range<usize>>,
         text: &str,
-        cx: &mut AppContext,
-        window_id: usize,
+        cx: &mut WindowContext<'a, 'b>,
         view_id: usize,
     ) {
-        let mut cx = ViewContext::new(cx, window_id, view_id);
+        let mut cx = ViewContext::new(cx, view_id);
         View::replace_text_in_range(self, range, text, &mut cx)
     }
 
-    fn replace_and_mark_text_in_range(
+    fn replace_and_mark_text_in_range<'a, 'b>(
         &mut self,
         range: Option<Range<usize>>,
         new_text: &str,
         new_selected_range: Option<Range<usize>>,
-        cx: &mut AppContext,
-        window_id: usize,
+        cx: &mut WindowContext<'a, 'b>,
         view_id: usize,
     ) {
-        let mut cx = ViewContext::new(cx, window_id, view_id);
+        let mut cx = ViewContext::new(cx, view_id);
         View::replace_and_mark_text_in_range(self, range, new_text, new_selected_range, &mut cx)
     }
 }
@@ -3429,25 +3339,41 @@ impl<M> DerefMut for ModelContext<'_, M> {
     }
 }
 
-pub struct ViewContext<'a, T: ?Sized> {
-    app: &'a mut AppContext,
-    window_id: usize,
+pub struct ViewContext<'a, 'b, T: ?Sized> {
+    window_context: WindowContext<'a, 'b>,
     view_id: usize,
     view_type: PhantomData<T>,
 }
 
-impl<'a, T: View> ViewContext<'a, T> {
-    fn new(app: &'a mut AppContext, window_id: usize, view_id: usize) -> Self {
+impl<'a, 'b, T: View> Deref for ViewContext<'a, 'b, T> {
+    type Target = WindowContext<'a, 'b>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.window_context
+    }
+}
+
+impl<'a, 'b, T: View> DerefMut for ViewContext<'a, 'b, T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.window_context
+    }
+}
+
+impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
+    fn new(window_context: &'b mut WindowContext<'a, 'b>, view_id: usize) -> Self {
         Self {
-            app,
-            window_id,
+            window_context,
             view_id,
             view_type: PhantomData,
         }
     }
 
     pub fn handle(&self) -> ViewHandle<T> {
-        ViewHandle::new(self.window_id, self.view_id, &self.app.ref_counts)
+        ViewHandle::new(
+            self.window_id,
+            self.view_id,
+            &self.window_context.ref_counts,
+        )
     }
 
     pub fn weak_handle(&self) -> WeakViewHandle<T> {
@@ -3455,7 +3381,7 @@ impl<'a, T: View> ViewContext<'a, T> {
     }
 
     pub fn parent(&self) -> Option<usize> {
-        self.app.parent(self.window_id, self.view_id)
+        self.window_context.parent(self.window_id, self.view_id)
     }
 
     pub fn window_id(&self) -> usize {
@@ -3467,42 +3393,44 @@ impl<'a, T: View> ViewContext<'a, T> {
     }
 
     pub fn foreground(&self) -> &Rc<executor::Foreground> {
-        self.app.foreground()
+        self.window_context.foreground()
     }
 
     pub fn background_executor(&self) -> &Arc<executor::Background> {
-        &self.app.background
+        &self.window_context.background
     }
 
     pub fn platform(&self) -> &Arc<dyn Platform> {
-        self.app.platform()
+        self.window_context.platform()
     }
 
     pub fn prompt_for_paths(
         &self,
         options: PathPromptOptions,
     ) -> oneshot::Receiver<Option<Vec<PathBuf>>> {
-        self.app.prompt_for_paths(options)
+        self.window_context.prompt_for_paths(options)
     }
 
     pub fn prompt_for_new_path(&self, directory: &Path) -> oneshot::Receiver<Option<PathBuf>> {
-        self.app.prompt_for_new_path(directory)
+        self.window_context.prompt_for_new_path(directory)
     }
 
     pub fn reveal_path(&self, path: &Path) {
-        self.app.reveal_path(path)
+        self.window_context.reveal_path(path)
     }
 
     pub fn focus(&mut self, handle: &AnyViewHandle) {
-        self.app.focus(handle.window_id, Some(handle.view_id));
+        self.window_context
+            .focus(handle.window_id, Some(handle.view_id));
     }
 
     pub fn focus_self(&mut self) {
-        self.app.focus(self.window_id, Some(self.view_id));
+        self.window_context
+            .focus(self.window_id, Some(self.view_id));
     }
 
     pub fn is_self_focused(&self) -> bool {
-        self.app.focused_view_id(self.window_id) == Some(self.view_id)
+        self.window.focused_view == Some(self.view_id)
     }
 
     pub fn is_child(&self, view: impl Into<AnyViewHandle>) -> bool {
@@ -3516,7 +3444,7 @@ impl<'a, T: View> ViewContext<'a, T> {
     }
 
     pub fn blur(&mut self) {
-        self.app.focus(self.window_id, None);
+        self.window_context.focus(self.window_id, None);
     }
 
     pub fn on_window_should_close<F>(&mut self, mut callback: F)
@@ -3543,7 +3471,7 @@ impl<'a, T: View> ViewContext<'a, T> {
         S: Entity,
         F: FnOnce(&mut ModelContext<S>) -> S,
     {
-        self.app.add_model(build_model)
+        self.window_context.add_model(build_model)
     }
 
     pub fn add_view<S, F>(&mut self, build_view: F) -> ViewHandle<S>
@@ -3551,7 +3479,7 @@ impl<'a, T: View> ViewContext<'a, T> {
         S: View,
         F: FnOnce(&mut ViewContext<S>) -> S,
     {
-        self.app
+        self.window_context
             .build_and_insert_view(self.window_id, ParentId::View(self.view_id), |cx| {
                 Some(build_view(cx))
             })
@@ -3563,8 +3491,11 @@ impl<'a, T: View> ViewContext<'a, T> {
         S: View,
         F: FnOnce(&mut ViewContext<S>) -> Option<S>,
     {
-        self.app
-            .build_and_insert_view(self.window_id, ParentId::View(self.view_id), build_view)
+        self.window_context.build_and_insert_view(
+            self.window_id,
+            ParentId::View(self.view_id),
+            build_view,
+        )
     }
 
     pub fn reparent(&mut self, view_handle: &AnyViewHandle) {
@@ -3605,7 +3536,7 @@ impl<'a, T: View> ViewContext<'a, T> {
         F: 'static + FnMut(&mut T, H, &E::Event, &mut ViewContext<T>),
     {
         let subscriber = self.weak_handle();
-        self.app
+        self.window_context
             .subscribe_internal(handle, move |emitter, event, cx| {
                 if let Some(subscriber) = subscriber.upgrade(cx) {
                     subscriber.update(cx, |subscriber, cx| {
@@ -3625,16 +3556,17 @@ impl<'a, T: View> ViewContext<'a, T> {
         F: 'static + FnMut(&mut T, H, &mut ViewContext<T>),
     {
         let observer = self.weak_handle();
-        self.app.observe_internal(handle, move |observed, cx| {
-            if let Some(observer) = observer.upgrade(cx) {
-                observer.update(cx, |observer, cx| {
-                    callback(observer, observed, cx);
-                });
-                true
-            } else {
-                false
-            }
-        })
+        self.window_context
+            .observe_internal(handle, move |observed, cx| {
+                if let Some(observer) = observer.upgrade(cx) {
+                    observer.update(cx, |observer, cx| {
+                        callback(observer, observed, cx);
+                    });
+                    true
+                } else {
+                    false
+                }
+            })
     }
 
     pub fn observe_global<G, F>(&mut self, mut callback: F) -> Subscription
@@ -3643,7 +3575,7 @@ impl<'a, T: View> ViewContext<'a, T> {
         F: 'static + FnMut(&mut T, &mut ViewContext<T>),
     {
         let observer = self.weak_handle();
-        self.app.observe_global::<G, _>(move |cx| {
+        self.window_context.observe_global::<G, _>(move |cx| {
             if let Some(observer) = observer.upgrade(cx) {
                 observer.update(cx, |observer, cx| callback(observer, cx));
             }
@@ -3656,7 +3588,7 @@ impl<'a, T: View> ViewContext<'a, T> {
         V: View,
     {
         let observer = self.weak_handle();
-        self.app
+        self.window_context
             .observe_focus(handle, move |observed, focused, cx| {
                 if let Some(observer) = observer.upgrade(cx) {
                     observer.update(cx, |observer, cx| {
@@ -3676,13 +3608,14 @@ impl<'a, T: View> ViewContext<'a, T> {
         F: 'static + FnMut(&mut T, &E, &mut ViewContext<T>),
     {
         let observer = self.weak_handle();
-        self.app.observe_release(handle, move |released, cx| {
-            if let Some(observer) = observer.upgrade(cx) {
-                observer.update(cx, |observer, cx| {
-                    callback(observer, released, cx);
-                });
-            }
-        })
+        self.window_context
+            .observe_release(handle, move |released, cx| {
+                if let Some(observer) = observer.upgrade(cx) {
+                    observer.update(cx, |observer, cx| {
+                        callback(observer, released, cx);
+                    });
+                }
+            })
     }
 
     pub fn observe_actions<F>(&mut self, mut callback: F) -> Subscription

crates/gpui/src/app/test_app_context.rs 🔗

@@ -23,8 +23,8 @@ use crate::{
     platform,
     platform::{Appearance, Event, InputHandler, KeyDownEvent, Platform},
     Action, AnyViewHandle, AppContext, Entity, FontCache, Handle, ModelContext, ModelHandle,
-    ReadModelWith, ReadViewWith, RenderContext, Task, UpdateModel, UpdateView, View, ViewContext,
-    ViewHandle, WeakHandle,
+    ReadModelWith, ReadViewWith, Task, UpdateModel, UpdateView, View, ViewContext, ViewHandle,
+    WeakHandle,
 };
 use collections::BTreeMap;
 

crates/gpui/src/app/window.rs 🔗

@@ -1,23 +1,20 @@
 use crate::{
     app::WindowInvalidation,
     elements::Element,
-    font_cache::FontCache,
     geometry::rect::RectF,
     json::{self, ToJson},
     keymap_matcher::{Keystroke, MatchResult},
     platform::{
-        self, Appearance, CursorStyle, Event, FontSystem, MouseButton, MouseMovedEvent,
-        PromptLevel, WindowBounds,
+        self, Appearance, CursorStyle, Event, KeyDownEvent, KeyUpEvent, ModifiersChangedEvent,
+        MouseButton, MouseMovedEvent, PromptLevel, WindowBounds,
     },
     scene::{
         CursorRegion, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseEvent, MouseHover,
         MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, Scene,
     },
     text_layout::TextLayoutCache,
-    Action, AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AnyWeakViewHandle, AppContext,
-    AssetCache, ElementBox, Entity, ModelHandle, MouseRegion, MouseRegionId, MouseState, ParentId,
-    ReadModel, ReadView, RenderContext, RenderParams, SceneBuilder, UpgradeModelHandle,
-    UpgradeViewHandle, View, ViewHandle, WeakModelHandle, WeakViewHandle,
+    Action, AnyView, AnyViewHandle, AnyWeakViewHandle, AppContext, ElementBox, MouseRegion,
+    MouseRegionId, RenderParams, SceneBuilder, View,
 };
 use anyhow::bail;
 use collections::{HashMap, HashSet};
@@ -29,11 +26,7 @@ use sqlez::{
     bindable::{Bind, Column, StaticColumnCount},
     statement::Statement,
 };
-use std::{
-    marker::PhantomData,
-    ops::{Deref, DerefMut, Range},
-    sync::Arc,
-};
+use std::ops::{Deref, DerefMut, Range};
 use uuid::Uuid;
 
 pub struct Window {
@@ -44,19 +37,17 @@ pub struct Window {
     pub(crate) is_fullscreen: bool,
     pub(crate) invalidation: Option<WindowInvalidation>,
     pub(crate) platform_window: Box<dyn platform::Window>,
-    pub(crate) rendered_views: HashMap<usize, ElementBox>,
+    pub(crate) rendered_views: HashMap<usize, Box<dyn RenderedView>>,
+    titlebar_height: f32,
+    appearance: Appearance,
     cursor_regions: Vec<CursorRegion>,
     mouse_regions: Vec<(MouseRegion, usize)>,
-    font_cache: Arc<FontCache>,
-    text_layout_cache: TextLayoutCache,
-    asset_cache: Arc<AssetCache>,
     last_mouse_moved_event: Option<Event>,
     hovered_region_ids: HashSet<MouseRegionId>,
     clicked_region_ids: HashSet<MouseRegionId>,
     clicked_button: Option<MouseButton>,
     mouse_position: Vector2F,
-    titlebar_height: f32,
-    appearance: Appearance,
+    text_layout_cache: TextLayoutCache,
 }
 
 impl Window {
@@ -64,9 +55,6 @@ impl Window {
         window_id: usize,
         root_view: AnyViewHandle,
         platform_window: Box<dyn platform::Window>,
-        font_cache: Arc<FontCache>,
-        text_layout_cache: TextLayoutCache,
-        asset_cache: Arc<AssetCache>,
         cx: &mut AppContext,
     ) -> Self {
         let focused_view_id = Some(root_view.id());
@@ -83,9 +71,7 @@ impl Window {
             rendered_views: cx.render_views(window_id, titlebar_height, appearance),
             cursor_regions: Default::default(),
             mouse_regions: Default::default(),
-            font_cache,
-            text_layout_cache,
-            asset_cache,
+            text_layout_cache: TextLayoutCache::new(cx.font_system.clone()),
             last_mouse_moved_event: None,
             hovered_region_ids: Default::default(),
             clicked_region_ids: Default::default(),
@@ -100,7 +86,7 @@ impl Window {
 pub struct WindowContext<'a: 'b, 'b> {
     app_context: &'a mut AppContext,
     pub(crate) window: &'b mut Window, // TODO: make this private?
-    window_id: usize,
+    pub(crate) window_id: usize,
 }
 
 impl Deref for WindowContext<'_, '_> {
@@ -126,9 +112,19 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> {
         }
     }
 
+    pub fn update_any_view<F, T>(&mut self, view_id: usize, f: F) -> Option<T>
+    where
+        F: FnOnce(&mut dyn AnyView, &mut Self) -> T,
+    {
+        let view = self.views.remove(&(self.window_id, view_id))?;
+        let result = f(view.as_any_mut(), self);
+        self.views.insert((self.window_id, view_id), view);
+        Some(result)
+    }
+
     pub fn dispatch_keystroke(&mut self, keystroke: &Keystroke) -> bool {
         let window_id = self.window_id;
-        if let Some(focused_view_id) = self.focused_view_id(window_id) {
+        if let Some(focused_view_id) = self.focused_view_id() {
             let dispatch_path = self
                 .ancestors(window_id, focused_view_id)
                 .filter_map(|view_id| {
@@ -511,20 +507,71 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> {
         any_event_handled
     }
 
-    pub fn build_event_context<'c>(
-        &'c mut self,
-        notified_views: &'c mut HashSet<usize>,
-    ) -> EventContext<'c> {
-        EventContext {
-            font_cache: &self.window.font_cache,
-            text_layout_cache: &self.window.text_layout_cache,
-            view_stack: Default::default(),
-            notified_views,
-            notify_count: 0,
-            handled: false,
-            window_id: self.window_id,
-            app: self,
+    pub fn dispatch_key_down(&mut self, window_id: usize, event: &KeyDownEvent) -> bool {
+        if let Some(focused_view_id) = self.window.focused_view_id {
+            for view_id in self
+                .ancestors(window_id, focused_view_id)
+                .collect::<Vec<_>>()
+            {
+                if let Some(mut view) = self.views.remove(&(window_id, view_id)) {
+                    let handled = view.key_down(event, self, view_id);
+                    self.views.insert((window_id, view_id), view);
+                    if handled {
+                        return true;
+                    }
+                } else {
+                    log::error!("view {} does not exist", view_id)
+                }
+            }
+        }
+
+        false
+    }
+
+    pub fn dispatch_key_up(&mut self, window_id: usize, event: &KeyUpEvent) -> bool {
+        if let Some(focused_view_id) = self.window.fo {
+            for view_id in self
+                .ancestors(window_id, focused_view_id)
+                .collect::<Vec<_>>()
+            {
+                if let Some(mut view) = self.views.remove(&(window_id, view_id)) {
+                    let handled = view.key_up(event, self, view_id);
+                    self.views.insert((window_id, view_id), view);
+                    if handled {
+                        return true;
+                    }
+                } else {
+                    log::error!("view {} does not exist", view_id)
+                }
+            }
+        }
+
+        false
+    }
+
+    pub fn dispatch_modifiers_changed(
+        &mut self,
+        window_id: usize,
+        event: &ModifiersChangedEvent,
+    ) -> bool {
+        if let Some(focused_view_id) = self.window.focused_view_id {
+            for view_id in self
+                .ancestors(window_id, focused_view_id)
+                .collect::<Vec<_>>()
+            {
+                if let Some(mut view) = self.views.remove(&(window_id, view_id)) {
+                    let handled = view.modifiers_changed(event, self, view_id);
+                    self.views.insert((window_id, view_id), view);
+                    if handled {
+                        return true;
+                    }
+                } else {
+                    log::error!("view {} does not exist", view_id)
+                }
+            }
         }
+
+        false
     }
 
     pub fn invalidate(&mut self, invalidation: &mut WindowInvalidation, appearance: Appearance) {
@@ -593,113 +640,56 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> {
         }
     }
 
-    pub fn build_scene(&mut self, refreshing: bool) -> Scene {
+    pub fn build_scene(&mut self) -> Scene {
         let window_size = self.window.platform_window.content_size();
         let scale_factor = self.window.platform_window.scale_factor();
 
-        let mut scene_builder = SceneBuilder::new(scale_factor);
+        let root_view_id = self.window.root_view.id();
+        let rendered_root = self.window.rendered_views.remove(&root_view_id).unwrap();
+        rendered_root.layout(root_view_id, SizeConstraint::strict(window_size), self);
 
-        if let Some(root_view_id) = self.root_view_id(self.window_id) {
-            self.layout(window_size, refreshing, self);
-            let mut paint_cx = self.build_paint_context(&mut scene_builder, window_size);
-            paint_cx.paint(
-                root_view_id,
-                Vector2F::zero(),
-                RectF::new(Vector2F::zero(), window_size),
-            );
-            self.window.text_layout_cache.finish_frame();
-            let scene = scene_builder.build();
-            self.window.cursor_regions = scene.cursor_regions();
-            self.window.mouse_regions = scene.mouse_regions();
-
-            // window.is_topmost for the mouse moved event's postion?
-            if self.window_is_active(self.window_id) {
-                if let Some(event) = self.window.last_mouse_moved_event.clone() {
-                    self.dispatch_event(event, true);
-                }
+        let mut scene_builder = SceneBuilder::new(scale_factor);
+        let paint_bounds = RectF::from_points(Vector2F::zero(), window_size);
+        rendered_root.paint(
+            root_view_id,
+            &mut scene_builder,
+            paint_bounds,
+            paint_bounds,
+            self,
+        );
+
+        self.window.text_layout_cache.finish_frame();
+        let scene = scene_builder.build();
+        self.window.cursor_regions = scene.cursor_regions();
+        self.window.mouse_regions = scene.mouse_regions();
+
+        if self.window_is_active() {
+            if let Some(event) = self.window.last_mouse_moved_event.clone() {
+                self.dispatch_event(event, true);
             }
-
-            scene
-        } else {
-            log::error!("could not find root_view_id for window {}", self.window_id);
-            scene_builder.build()
-        }
-    }
-
-    fn layout(&mut self, window_size: Vector2F, refreshing: bool, cx: &mut AppContext) {
-        if let Some(root_view_id) = cx.root_view_id(self.window_id) {
-            self.build_layout_context(window_size, refreshing, cx)
-                .layout(root_view_id, SizeConstraint::strict(window_size));
         }
-    }
 
-    pub fn build_layout_context<'c>(
-        &'c mut self,
-        window_size: Vector2F,
-        refreshing: bool,
-        cx: &'c mut AppContext,
-    ) -> LayoutContext<'c> {
-        LayoutContext {
-            window_id: self.window_id,
-            rendered_views: &mut self.window.rendered_views,
-            font_cache: &self.font_cache,
-            font_system: cx.platform().fonts(),
-            text_layout_cache: &self.window.text_layout_cache,
-            asset_cache: &self.window.asset_cache,
-            view_stack: Vec::new(),
-            refreshing,
-            hovered_region_ids: self.window.hovered_region_ids.clone(),
-            clicked_region_ids: self
-                .window
-                .clicked_button
-                .map(|button| (self.window.clicked_region_ids.clone(), button)),
-            titlebar_height: self.window.titlebar_height,
-            appearance: self.window.appearance,
-            window_size,
-            app: cx,
-        }
-    }
-
-    pub fn build_paint_context<'c>(
-        &'c mut self,
-        scene: &'c mut SceneBuilder,
-        window_size: Vector2F,
-    ) -> PaintContext {
-        PaintContext {
-            scene,
-            window_size,
-            font_cache: &self.font_cache,
-            text_layout_cache: &self.window.text_layout_cache,
-            rendered_views: &mut self.window.rendered_views,
-            view_stack: Vec::new(),
-            app: self,
-        }
+        scene
     }
 
     pub fn rect_for_text_range(&self, range_utf16: Range<usize>) -> Option<RectF> {
-        self.focused_view_id(self.window_id).and_then(|view_id| {
-            let cx = MeasurementContext {
-                app: self,
-                rendered_views: &self.window.rendered_views,
-                window_id: self.window_id,
-            };
-            cx.rect_for_text_range(view_id, range_utf16)
-        })
+        todo!()
     }
 
     pub fn debug_elements(&self) -> Option<json::Value> {
-        let view = self.root_view(self.window_id)?;
-        Some(json!({
-            "root_view": view.debug_json(self),
-            "root_element": self.window.rendered_views.get(&view.id())
-                .map(|root_element| {
-                    root_element.debug(&DebugContext {
-                        rendered_views: &self.window.rendered_views,
-                        font_cache: &self.window.font_cache,
-                        app: self,
-                    })
-                })
-        }))
+        todo!()
+        // let view = self.root_view()?;
+        // Some(json!({
+        //     "root_view": view.debug_json(self),
+        //     "root_element": self.window.rendered_views.get(&view.id())
+        //         .map(|root_element| {
+        //             root_element.debug(&DebugContext {
+        //                 rendered_views: &self.window.rendered_views,
+        //                 font_cache: &self.window.font_cache,
+        //                 app: self,
+        //             })
+        //         })
+        // }))
     }
 
     pub fn set_window_title(&mut self, title: &str) {
@@ -720,6 +710,26 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> {
         self.window.platform_window.activate();
     }
 
+    pub fn window_is_active(&self) -> bool {
+        self.window.is_active
+    }
+
+    pub fn window_is_fullscreen(&self) -> bool {
+        self.window.is_fullscreen
+    }
+
+    pub fn root_view(&self, window_id: usize) -> &AnyViewHandle {
+        &self.window.root_view
+    }
+
+    pub fn root_view_id(&self) -> usize {
+        self.window.root_view.id()
+    }
+
+    pub fn focused_view_id(&self) -> Option<usize> {
+        self.window.focused_view_id
+    }
+
     pub fn window_bounds(&self) -> WindowBounds {
         self.window.platform_window.bounds()
     }
@@ -754,330 +764,48 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> {
     }
 }
 
-pub struct LayoutContext<'a> {
-    window_id: usize,
-    rendered_views: &'a mut HashMap<usize, ElementBox>,
-    view_stack: Vec<usize>,
-    pub font_cache: &'a Arc<FontCache>,
-    pub font_system: Arc<dyn FontSystem>,
-    pub text_layout_cache: &'a TextLayoutCache,
-    pub asset_cache: &'a AssetCache,
-    pub app: &'a mut AppContext,
-    pub refreshing: bool,
-    pub window_size: Vector2F,
-    titlebar_height: f32,
-    appearance: Appearance,
-    hovered_region_ids: HashSet<MouseRegionId>,
-    clicked_region_ids: Option<(HashSet<MouseRegionId>, MouseButton)>,
-}
-
-impl<'a> LayoutContext<'a> {
-    pub fn mouse_state<Tag: 'static>(&self, region_id: usize) -> MouseState {
-        let view_id = self.view_stack.last().unwrap();
-
-        let region_id = MouseRegionId::new::<Tag>(*view_id, region_id);
-        MouseState {
-            hovered: self.hovered_region_ids.contains(&region_id),
-            clicked: self.clicked_region_ids.as_ref().and_then(|(ids, button)| {
-                if ids.contains(&region_id) {
-                    Some(*button)
-                } else {
-                    None
-                }
-            }),
-            accessed_hovered: false,
-            accessed_clicked: false,
-        }
-    }
-
-    fn layout(&mut self, view_id: usize, constraint: SizeConstraint) -> Vector2F {
-        let print_error = |view_id| {
-            format!(
-                "{} with id {}",
-                self.app.name_for_view(self.window_id, view_id).unwrap(),
-                view_id,
-            )
-        };
-        match (
-            self.view_stack.last(),
-            self.app.parents.get(&(self.window_id, view_id)),
-        ) {
-            (Some(layout_parent), Some(ParentId::View(app_parent))) => {
-                if layout_parent != app_parent {
-                    panic!(
-                        "View {} was laid out with parent {} when it was constructed with parent {}",
-                        print_error(view_id),
-                        print_error(*layout_parent),
-                        print_error(*app_parent))
-                }
-            }
-            (None, Some(ParentId::View(app_parent))) => panic!(
-                "View {} was laid out without a parent when it was constructed with parent {}",
-                print_error(view_id),
-                print_error(*app_parent)
-            ),
-            (Some(layout_parent), Some(ParentId::Root)) => panic!(
-                "View {} was laid out with parent {} when it was constructed as a window root",
-                print_error(view_id),
-                print_error(*layout_parent),
-            ),
-            (_, None) => panic!(
-                "View {} did not have a registered parent in the app context",
-                print_error(view_id),
-            ),
-            _ => {}
-        }
-
-        self.view_stack.push(view_id);
-        let mut rendered_view = self.rendered_views.remove(&view_id).unwrap();
-        let size = rendered_view.layout(constraint, self);
-        self.rendered_views.insert(view_id, rendered_view);
-        self.view_stack.pop();
-        size
-    }
-
-    pub fn render<F, V, T>(&mut self, handle: &ViewHandle<V>, f: F) -> T
-    where
-        F: FnOnce(&mut V, &mut RenderContext<V>) -> T,
-        V: View,
-    {
-        handle.update(self.app, |view, cx| {
-            let mut render_cx = RenderContext {
-                app: cx,
-                window_id: handle.window_id(),
-                view_id: handle.id(),
-                view_type: PhantomData,
-                titlebar_height: self.titlebar_height,
-                hovered_region_ids: self.hovered_region_ids.clone(),
-                clicked_region_ids: self.clicked_region_ids.clone(),
-                refreshing: self.refreshing,
-                appearance: self.appearance,
-            };
-            f(view, &mut render_cx)
-        })
-    }
-}
-
-impl<'a> Deref for LayoutContext<'a> {
-    type Target = AppContext;
-
-    fn deref(&self) -> &Self::Target {
-        self.app
-    }
-}
-
-impl<'a> DerefMut for LayoutContext<'a> {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        self.app
-    }
-}
-
-impl<'a> ReadView for LayoutContext<'a> {
-    fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
-        self.app.read_view(handle)
-    }
-}
-
-impl<'a> ReadModel for LayoutContext<'a> {
-    fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
-        self.app.read_model(handle)
-    }
-}
-
-impl<'a> UpgradeModelHandle for LayoutContext<'a> {
-    fn upgrade_model_handle<T: Entity>(
+pub trait RenderedView {
+    fn layout(
         &self,
-        handle: &WeakModelHandle<T>,
-    ) -> Option<ModelHandle<T>> {
-        self.app.upgrade_model_handle(handle)
-    }
-
-    fn model_handle_is_upgradable<T: Entity>(&self, handle: &WeakModelHandle<T>) -> bool {
-        self.app.model_handle_is_upgradable(handle)
-    }
-
-    fn upgrade_any_model_handle(&self, handle: &AnyWeakModelHandle) -> Option<AnyModelHandle> {
-        self.app.upgrade_any_model_handle(handle)
-    }
-}
-
-impl<'a> UpgradeViewHandle for LayoutContext<'a> {
-    fn upgrade_view_handle<T: View>(&self, handle: &WeakViewHandle<T>) -> Option<ViewHandle<T>> {
-        self.app.upgrade_view_handle(handle)
-    }
-
-    fn upgrade_any_view_handle(&self, handle: &crate::AnyWeakViewHandle) -> Option<AnyViewHandle> {
-        self.app.upgrade_any_view_handle(handle)
-    }
-}
-
-pub struct PaintContext<'a> {
-    rendered_views: &'a mut HashMap<usize, ElementBox>,
-    view_stack: Vec<usize>,
-    pub window_size: Vector2F,
-    pub scene: &'a mut SceneBuilder,
-    pub font_cache: &'a FontCache,
-    pub text_layout_cache: &'a TextLayoutCache,
-    pub app: &'a AppContext,
-}
-
-impl<'a> PaintContext<'a> {
-    fn paint(&mut self, view_id: usize, origin: Vector2F, visible_bounds: RectF) {
-        if let Some(mut tree) = self.rendered_views.remove(&view_id) {
-            self.view_stack.push(view_id);
-            tree.paint(origin, visible_bounds, self);
-            self.rendered_views.insert(view_id, tree);
-            self.view_stack.pop();
-        }
-    }
-
-    #[inline]
-    pub fn paint_stacking_context<F>(
-        &mut self,
-        clip_bounds: Option<RectF>,
-        z_index: Option<usize>,
-        f: F,
-    ) where
-        F: FnOnce(&mut Self),
-    {
-        self.scene.push_stacking_context(clip_bounds, z_index);
-        f(self);
-        self.scene.pop_stacking_context();
-    }
-
-    #[inline]
-    pub fn paint_layer<F>(&mut self, clip_bounds: Option<RectF>, f: F)
-    where
-        F: FnOnce(&mut Self),
-    {
-        self.scene.push_layer(clip_bounds);
-        f(self);
-        self.scene.pop_layer();
-    }
-
-    pub fn current_view_id(&self) -> usize {
-        *self.view_stack.last().unwrap()
-    }
-}
-
-impl<'a> Deref for PaintContext<'a> {
-    type Target = AppContext;
-
-    fn deref(&self) -> &Self::Target {
-        self.app
-    }
-}
-
-pub struct EventContext<'a> {
-    pub font_cache: &'a FontCache,
-    pub text_layout_cache: &'a TextLayoutCache,
-    pub app: &'a mut AppContext,
-    pub window_id: usize,
-    pub notify_count: usize,
-    view_stack: Vec<usize>,
-    handled: bool,
-    notified_views: &'a mut HashSet<usize>,
-}
-
-impl<'a> EventContext<'a> {
-    fn with_current_view<F, T>(&mut self, view_id: usize, f: F) -> T
-    where
-        F: FnOnce(&mut Self) -> T,
-    {
-        self.view_stack.push(view_id);
-        let result = f(self);
-        self.view_stack.pop();
-        result
-    }
-
-    pub fn window_id(&self) -> usize {
-        self.window_id
-    }
-
-    pub fn view_id(&self) -> Option<usize> {
-        self.view_stack.last().copied()
-    }
-
-    pub fn is_parent_view_focused(&self) -> bool {
-        if let Some(parent_view_id) = self.view_stack.last() {
-            self.app.focused_view_id(self.window_id) == Some(*parent_view_id)
-        } else {
-            false
-        }
-    }
-
-    pub fn focus_parent_view(&mut self) {
-        if let Some(parent_view_id) = self.view_stack.last() {
-            self.app.focus(self.window_id, Some(*parent_view_id))
-        }
-    }
-
-    pub fn dispatch_any_action(&mut self, action: Box<dyn Action>) {
-        self.app
-            .dispatch_any_action_at(self.window_id, *self.view_stack.last().unwrap(), action)
-    }
-
-    pub fn dispatch_action<A: Action>(&mut self, action: A) {
-        self.dispatch_any_action(Box::new(action));
-    }
-
-    pub fn notify(&mut self) {
-        self.notify_count += 1;
-        if let Some(view_id) = self.view_stack.last() {
-            self.notified_views.insert(*view_id);
-        }
-    }
-
-    pub fn notify_count(&self) -> usize {
-        self.notify_count
-    }
-
-    pub fn propagate_event(&mut self) {
-        self.handled = false;
-    }
-}
-
-impl<'a> Deref for EventContext<'a> {
-    type Target = AppContext;
-
-    fn deref(&self) -> &Self::Target {
-        self.app
-    }
-}
-
-impl<'a> DerefMut for EventContext<'a> {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        self.app
-    }
-}
-
-pub struct MeasurementContext<'a> {
-    app: &'a AppContext,
-    rendered_views: &'a HashMap<usize, ElementBox>,
-    pub window_id: usize,
+        view_id: usize,
+        constraint: SizeConstraint,
+        cx: &mut WindowContext,
+    ) -> Vector2F;
+    fn paint(
+        &self,
+        view_id: usize,
+        scene: &mut SceneBuilder,
+        bounds: RectF,
+        visible_bounds: RectF,
+        cx: &mut WindowContext,
+    );
 }
 
-impl<'a> Deref for MeasurementContext<'a> {
-    type Target = AppContext;
-
-    fn deref(&self) -> &Self::Target {
-        self.app
+impl<V: View> RenderedView for ElementBox<V> {
+    fn layout(
+        &self,
+        view_id: usize,
+        constraint: SizeConstraint,
+        cx: &mut WindowContext,
+    ) -> Vector2F {
+        cx.update_view_for_id(view_id, |view, cx| self.layout(view, constraint, cx))
+            .unwrap()
     }
-}
 
-impl<'a> MeasurementContext<'a> {
-    fn rect_for_text_range(&self, view_id: usize, range_utf16: Range<usize>) -> Option<RectF> {
-        let element = self.rendered_views.get(&view_id)?;
-        element.rect_for_text_range(range_utf16, self)
+    fn paint(
+        &self,
+        view_id: usize,
+        scene: &mut SceneBuilder,
+        bounds: RectF,
+        visible_bounds: RectF,
+        cx: &mut WindowContext,
+    ) {
+        cx.update_view_for_id(view_id, |view, cx| {
+            self.paint(view, scene, bounds, visible_bounds, cx)
+        })
     }
 }
 
-pub struct DebugContext<'a> {
-    rendered_views: &'a HashMap<usize, ElementBox>,
-    pub font_cache: &'a FontCache,
-    pub app: &'a AppContext,
-}
-
 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
 pub enum Axis {
     #[default]
@@ -1235,88 +963,88 @@ impl ChildView {
     }
 }
 
-impl Element for ChildView {
-    type LayoutState = bool;
-    type PaintState = ();
-
-    fn layout(
-        &mut self,
-        constraint: SizeConstraint,
-        cx: &mut LayoutContext,
-    ) -> (Vector2F, Self::LayoutState) {
-        if cx.rendered_views.contains_key(&self.view.id()) {
-            let size = cx.layout(self.view.id(), constraint);
-            (size, true)
-        } else {
-            log::error!(
-                "layout called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
-                self.view.id(),
-                self.view_name
-            );
-            (Vector2F::zero(), false)
-        }
-    }
-
-    fn paint(
-        &mut self,
-        bounds: RectF,
-        visible_bounds: RectF,
-        view_is_valid: &mut Self::LayoutState,
-        cx: &mut PaintContext,
-    ) {
-        if *view_is_valid {
-            cx.paint(self.view.id(), bounds.origin(), visible_bounds);
-        } else {
-            log::error!(
-                "paint called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
-                self.view.id(),
-                self.view_name
-            );
-        }
-    }
-
-    fn rect_for_text_range(
-        &self,
-        range_utf16: Range<usize>,
-        _: RectF,
-        _: RectF,
-        view_is_valid: &Self::LayoutState,
-        _: &Self::PaintState,
-        cx: &MeasurementContext,
-    ) -> Option<RectF> {
-        if *view_is_valid {
-            cx.rect_for_text_range(self.view.id(), range_utf16)
-        } else {
-            log::error!(
-                "rect_for_text_range called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
-                self.view.id(),
-                self.view_name
-            );
-            None
-        }
-    }
-
-    fn debug(
-        &self,
-        bounds: RectF,
-        _: &Self::LayoutState,
-        _: &Self::PaintState,
-        cx: &DebugContext,
-    ) -> serde_json::Value {
-        json!({
-            "type": "ChildView",
-            "view_id": self.view.id(),
-            "bounds": bounds.to_json(),
-            "view": if let Some(view) = self.view.upgrade(cx.app) {
-                view.debug_json(cx.app)
-            } else {
-                json!(null)
-            },
-            "child": if let Some(view) = cx.rendered_views.get(&self.view.id()) {
-                view.debug(cx)
-            } else {
-                json!(null)
-            }
-        })
-    }
-}
+// impl Element for ChildView {
+//     type LayoutState = bool;
+//     type PaintState = ();
+
+//     fn layout(
+//         &mut self,
+//         constraint: SizeConstraint,
+//         cx: &mut LayoutContext,
+//     ) -> (Vector2F, Self::LayoutState) {
+//         if cx.rendered_views.contains_key(&self.view.id()) {
+//             let size = cx.layout(self.view.id(), constraint);
+//             (size, true)
+//         } else {
+//             log::error!(
+//                 "layout called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
+//                 self.view.id(),
+//                 self.view_name
+//             );
+//             (Vector2F::zero(), false)
+//         }
+//     }
+
+//     fn paint(
+//         &mut self,
+//         bounds: RectF,
+//         visible_bounds: RectF,
+//         view_is_valid: &mut Self::LayoutState,
+//         cx: &mut PaintContext,
+//     ) {
+//         if *view_is_valid {
+//             cx.paint(self.view.id(), bounds.origin(), visible_bounds);
+//         } else {
+//             log::error!(
+//                 "paint called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
+//                 self.view.id(),
+//                 self.view_name
+//             );
+//         }
+//     }
+
+//     fn rect_for_text_range(
+//         &self,
+//         range_utf16: Range<usize>,
+//         _: RectF,
+//         _: RectF,
+//         view_is_valid: &Self::LayoutState,
+//         _: &Self::PaintState,
+//         cx: &MeasurementContext,
+//     ) -> Option<RectF> {
+//         if *view_is_valid {
+//             cx.rect_for_text_range(self.view.id(), range_utf16)
+//         } else {
+//             log::error!(
+//                 "rect_for_text_range called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
+//                 self.view.id(),
+//                 self.view_name
+//             );
+//             None
+//         }
+//     }
+
+//     fn debug(
+//         &self,
+//         bounds: RectF,
+//         _: &Self::LayoutState,
+//         _: &Self::PaintState,
+//         cx: &DebugContext,
+//     ) -> serde_json::Value {
+//         json!({
+//             "type": "ChildView",
+//             "view_id": self.view.id(),
+//             "bounds": bounds.to_json(),
+//             "view": if let Some(view) = self.view.upgrade(cx.app) {
+//                 view.debug_json(cx.app)
+//             } else {
+//                 json!(null)
+//             },
+//             "child": if let Some(view) = cx.rendered_views.get(&self.view.id()) {
+//                 view.debug(cx)
+//             } else {
+//                 json!(null)
+//             }
+//         })
+//     }
+// }

crates/gpui/src/elements.rs 🔗

@@ -32,42 +32,52 @@ use crate::{
         rect::RectF,
         vector::{vec2f, Vector2F},
     },
-    json, Action, DebugContext, EventContext, LayoutContext, PaintContext, RenderContext,
-    SizeConstraint, View,
+    json, Action, RenderContext, SceneBuilder, SizeConstraint, View, ViewContext,
 };
 use core::panic;
 use json::ToJson;
-use std::{
-    any::Any,
-    borrow::Cow,
-    cell::RefCell,
-    mem,
-    ops::{Deref, DerefMut, Range},
-    rc::Rc,
-};
+use std::{any::Any, borrow::Cow, cell::RefCell, marker::PhantomData, mem, ops::Range};
+
+trait AnyElement<V: View> {
+    fn layout(
+        &mut self,
+        view: &mut V,
+        constraint: SizeConstraint,
+        cx: &mut ViewContext<V>,
+    ) -> Vector2F;
+
+    fn paint(
+        &mut self,
+        view: &mut V,
+        scene: &mut SceneBuilder,
+        origin: Vector2F,
+        visible_bounds: RectF,
+        cx: &mut ViewContext<V>,
+    );
 
-trait AnyElement {
-    fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F;
-    fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext);
     fn rect_for_text_range(
         &self,
+        view: &V,
         range_utf16: Range<usize>,
-        cx: &MeasurementContext,
+        cx: &ViewContext<V>,
     ) -> Option<RectF>;
-    fn debug(&self, cx: &DebugContext) -> serde_json::Value;
+
+    fn debug(&self, view: &V, cx: &mut ViewContext<V>) -> serde_json::Value;
 
     fn size(&self) -> Vector2F;
+
     fn metadata(&self) -> Option<&dyn Any>;
 }
 
-pub trait Element {
+pub trait Element<V: View> {
     type LayoutState;
     type PaintState;
 
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        cx: &mut LayoutContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState);
 
     fn paint(
@@ -75,7 +85,8 @@ pub trait Element {
         bounds: RectF,
         visible_bounds: RectF,
         layout: &mut Self::LayoutState,
-        cx: &mut PaintContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState;
 
     fn rect_for_text_range(
@@ -85,7 +96,8 @@ pub trait Element {
         visible_bounds: RectF,
         layout: &Self::LayoutState,
         paint: &Self::PaintState,
-        cx: &MeasurementContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> Option<RectF>;
 
     fn metadata(&self) -> Option<&dyn Any> {
@@ -97,27 +109,28 @@ pub trait Element {
         bounds: RectF,
         layout: &Self::LayoutState,
         paint: &Self::PaintState,
-        cx: &DebugContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> serde_json::Value;
 
-    fn boxed(self) -> ElementBox
+    fn boxed(self) -> ElementBox<V>
     where
         Self: 'static + Sized,
     {
-        ElementBox(ElementRc {
+        ElementBox {
+            element: RefCell::new(Lifecycle::Init { element: self }),
             name: None,
-            element: Rc::new(RefCell::new(Lifecycle::Init { element: self })),
-        })
+        }
     }
 
-    fn named(self, name: impl Into<Cow<'static, str>>) -> ElementBox
+    fn named(self, name: impl Into<Cow<'static, str>>) -> ElementBox<V>
     where
         Self: 'static + Sized,
     {
-        ElementBox(ElementRc {
+        ElementBox {
+            element: RefCell::new(Lifecycle::Init { element: self }),
             name: Some(name.into()),
-            element: Rc::new(RefCell::new(Lifecycle::Init { element: self })),
-        })
+        }
     }
 
     fn constrained(self) -> ConstrainedBox
@@ -205,44 +218,41 @@ pub trait Element {
     }
 }
 
-pub enum Lifecycle<T: Element> {
+pub enum Lifecycle<V: View, E: Element<V>> {
     Empty,
     Init {
-        element: T,
+        element: E,
     },
     PostLayout {
-        element: T,
+        element: E,
         constraint: SizeConstraint,
         size: Vector2F,
-        layout: T::LayoutState,
+        layout: E::LayoutState,
     },
     PostPaint {
-        element: T,
+        element: E,
         constraint: SizeConstraint,
         bounds: RectF,
         visible_bounds: RectF,
-        layout: T::LayoutState,
-        paint: T::PaintState,
+        layout: E::LayoutState,
+        paint: E::PaintState,
     },
 }
 
-pub struct ElementBox(ElementRc);
-
-#[derive(Clone)]
-pub struct ElementRc {
-    name: Option<Cow<'static, str>>,
-    element: Rc<RefCell<dyn AnyElement>>,
-}
-
-impl<T: Element> AnyElement for Lifecycle<T> {
-    fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
+impl<V: View, E: Element<V>> AnyElement<V> for Lifecycle<V, E> {
+    fn layout(
+        &mut self,
+        view: &mut V,
+        constraint: SizeConstraint,
+        cx: &mut ViewContext<V>,
+    ) -> Vector2F {
         let result;
         *self = match mem::take(self) {
             Lifecycle::Empty => unreachable!(),
             Lifecycle::Init { mut element }
             | Lifecycle::PostLayout { mut element, .. }
             | Lifecycle::PostPaint { mut element, .. } => {
-                let (size, layout) = element.layout(constraint, cx);
+                let (size, layout) = element.layout(view, constraint, cx);
                 debug_assert!(size.x().is_finite());
                 debug_assert!(size.y().is_finite());
 
@@ -258,7 +268,13 @@ impl<T: Element> AnyElement for Lifecycle<T> {
         result
     }
 
-    fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext) {
+    fn paint(
+        &mut self,
+        view: &mut V,
+        origin: Vector2F,
+        visible_bounds: RectF,
+        cx: &mut ViewContext<V>,
+    ) {
         *self = match mem::take(self) {
             Lifecycle::PostLayout {
                 mut element,
@@ -267,7 +283,7 @@ impl<T: Element> AnyElement for Lifecycle<T> {
                 mut layout,
             } => {
                 let bounds = RectF::new(origin, size);
-                let paint = element.paint(bounds, visible_bounds, &mut layout, cx);
+                let paint = element.paint(view, bounds, visible_bounds, &mut layout, cx);
                 Lifecycle::PostPaint {
                     element,
                     constraint,
@@ -285,7 +301,7 @@ impl<T: Element> AnyElement for Lifecycle<T> {
                 ..
             } => {
                 let bounds = RectF::new(origin, bounds.size());
-                let paint = element.paint(bounds, visible_bounds, &mut layout, cx);
+                let paint = element.paint(view, bounds, visible_bounds, &mut layout, cx);
                 Lifecycle::PostPaint {
                     element,
                     constraint,
@@ -304,8 +320,9 @@ impl<T: Element> AnyElement for Lifecycle<T> {
 
     fn rect_for_text_range(
         &self,
+        view: &V,
         range_utf16: Range<usize>,
-        cx: &MeasurementContext,
+        cx: &mut ViewContext<V>,
     ) -> Option<RectF> {
         if let Lifecycle::PostPaint {
             element,
@@ -316,7 +333,15 @@ impl<T: Element> AnyElement for Lifecycle<T> {
             ..
         } = self
         {
-            element.rect_for_text_range(range_utf16, *bounds, *visible_bounds, layout, paint, cx)
+            element.rect_for_text_range(
+                view,
+                range_utf16,
+                *bounds,
+                *visible_bounds,
+                layout,
+                paint,
+                cx,
+            )
         } else {
             None
         }
@@ -339,7 +364,7 @@ impl<T: Element> AnyElement for Lifecycle<T> {
         }
     }
 
-    fn debug(&self, cx: &DebugContext) -> serde_json::Value {
+    fn debug(&self, view: &V, cx: &ViewContext<V>) -> serde_json::Value {
         match self {
             Lifecycle::PostPaint {
                 element,
@@ -349,7 +374,7 @@ impl<T: Element> AnyElement for Lifecycle<T> {
                 layout,
                 paint,
             } => {
-                let mut value = element.debug(*bounds, layout, paint, cx);
+                let mut value = element.debug(view, *bounds, layout, paint, cx);
                 if let json::Value::Object(map) = &mut value {
                     let mut new_map: crate::json::Map<String, serde_json::Value> =
                         Default::default();
@@ -371,72 +396,67 @@ impl<T: Element> AnyElement for Lifecycle<T> {
     }
 }
 
-impl<T: Element> Default for Lifecycle<T> {
+impl<V: View, E: Element<V>> Default for Lifecycle<V, E> {
     fn default() -> Self {
         Self::Empty
     }
 }
 
-impl ElementBox {
+pub struct ElementBox<V: View> {
+    element: RefCell<dyn AnyElement<V>>,
+    view_type: PhantomData<V>,
+    name: Option<Cow<'static, str>>,
+}
+
+impl<V: View> ElementBox<V> {
     pub fn name(&self) -> Option<&str> {
         self.0.name.as_deref()
     }
 
     pub fn metadata<T: 'static>(&self) -> Option<&T> {
-        let element = unsafe { &*self.0.element.as_ptr() };
-        element.metadata().and_then(|m| m.downcast_ref())
-    }
-}
-
-impl Clone for ElementBox {
-    fn clone(&self) -> Self {
-        ElementBox(self.0.clone())
-    }
-}
-
-impl From<ElementBox> for ElementRc {
-    fn from(val: ElementBox) -> Self {
-        val.0
+        // let element = unsafe { &*self.0.element.as_ptr() };
+        // element.metadata().and_then(|m| m.downcast_ref())
     }
-}
 
-impl Deref for ElementBox {
-    type Target = ElementRc;
-
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
-}
-
-impl DerefMut for ElementBox {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.0
-    }
-}
-
-impl ElementRc {
-    pub fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
-        self.element.borrow_mut().layout(constraint, cx)
+    pub fn layout(
+        &self,
+        view: &mut V,
+        constraint: SizeConstraint,
+        cx: &mut ViewContext<V>,
+    ) -> Vector2F {
+        self.element.borrow_mut().layout(view, constraint, cx)
     }
 
-    pub fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext) {
-        self.element.borrow_mut().paint(origin, visible_bounds, cx);
+    pub fn paint(
+        &self,
+        view: &mut V,
+        scene: &mut SceneBuilder,
+        origin: Vector2F,
+        visible_bounds: RectF,
+        cx: &mut ViewContext<V>,
+    ) {
+        self.element
+            .borrow_mut()
+            .paint(view, scene, origin, visible_bounds, cx);
     }
 
     pub fn rect_for_text_range(
         &self,
+        view: &V,
         range_utf16: Range<usize>,
-        cx: &MeasurementContext,
+        cx: &ViewContext<V>,
     ) -> Option<RectF> {
-        self.element.borrow().rect_for_text_range(range_utf16, cx)
+        self.element
+            .borrow()
+            .rect_for_text_range(view, range_utf16, cx)
     }
 
     pub fn size(&self) -> Vector2F {
         self.element.borrow().size()
     }
 
-    pub fn debug(&self, cx: &DebugContext) -> json::Value {
-        let mut value = self.element.borrow().debug(cx);
+    pub fn debug(&self, view: &V, cx: &ViewContext<V>) -> json::Value {
+        let mut value = self.element.borrow().debug(view, cx);
 
         if let Some(name) = &self.name {
             if let json::Value::Object(map) = &mut value {
@@ -460,26 +480,26 @@ impl ElementRc {
     }
 }
 
-pub trait ParentElement<'a>: Extend<ElementBox> + Sized {
-    fn add_children(&mut self, children: impl IntoIterator<Item = ElementBox>) {
+pub trait ParentElement<'a, V: View>: Extend<ElementBox<V>> + Sized {
+    fn add_children(&mut self, children: impl IntoIterator<Item = ElementBox<V>>) {
         self.extend(children);
     }
 
-    fn add_child(&mut self, child: ElementBox) {
+    fn add_child(&mut self, child: ElementBox<V>) {
         self.add_children(Some(child));
     }
 
-    fn with_children(mut self, children: impl IntoIterator<Item = ElementBox>) -> Self {
+    fn with_children(mut self, children: impl IntoIterator<Item = ElementBox<V>>) -> Self {
         self.add_children(children);
         self
     }
 
-    fn with_child(self, child: ElementBox) -> Self {
+    fn with_child(self, child: ElementBox<V>) -> Self {
         self.with_children(Some(child))
     }
 }
 
-impl<'a, T> ParentElement<'a> for T where T: Extend<ElementBox> {}
+impl<'a, V: View, T> ParentElement<'a, V> for T where T: Extend<ElementBox<V>> {}
 
 pub fn constrain_size_preserving_aspect_ratio(max_size: Vector2F, size: Vector2F) -> Vector2F {
     if max_size.x().is_infinite() && max_size.y().is_infinite() {

crates/gpui/src/elements/align.rs 🔗

@@ -1,20 +1,18 @@
 use crate::{
     geometry::{rect::RectF, vector::Vector2F},
-    json,
-    window::MeasurementContext,
-    DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
+    json, Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext,
 };
 use json::ToJson;
 
 use serde_json::json;
 
-pub struct Align {
-    child: ElementBox,
+pub struct Align<V: View> {
+    child: ElementBox<V>,
     alignment: Vector2F,
 }
 
-impl Align {
-    pub fn new(child: ElementBox) -> Self {
+impl<V: View> Align<V> {
+    pub fn new(child: ElementBox<V>) -> Self {
         Self {
             child,
             alignment: Vector2F::zero(),
@@ -42,18 +40,19 @@ impl Align {
     }
 }
 
-impl Element for Align {
+impl<V: View> Element<V> for Align<V> {
     type LayoutState = ();
     type PaintState = ();
 
     fn layout(
         &mut self,
+        view: &mut V,
         mut constraint: SizeConstraint,
-        cx: &mut LayoutContext,
+        cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         let mut size = constraint.max;
         constraint.min = Vector2F::zero();
-        let child_size = self.child.layout(constraint, cx);
+        let child_size = self.child.layout(view, constraint, cx);
         if size.x().is_infinite() {
             size.set_x(child_size.x());
         }
@@ -65,10 +64,12 @@ impl Element for Align {
 
     fn paint(
         &mut self,
+        view: &mut V,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
-        cx: &mut PaintContext,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         let my_center = bounds.size() / 2.;
         let my_target = my_center + my_center * self.alignment;
@@ -77,6 +78,8 @@ impl Element for Align {
         let child_target = child_center + child_center * self.alignment;
 
         self.child.paint(
+            view,
+            scene,
             bounds.origin() - (child_target - my_target),
             visible_bounds,
             cx,
@@ -85,28 +88,30 @@ impl Element for Align {
 
     fn rect_for_text_range(
         &self,
+        view: &V,
         range_utf16: std::ops::Range<usize>,
         _: RectF,
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &MeasurementContext,
+        cx: &ViewContext<V>,
     ) -> Option<RectF> {
-        self.child.rect_for_text_range(range_utf16, cx)
+        self.child.rect_for_text_range(view, range_utf16, cx)
     }
 
     fn debug(
         &self,
+        view: &V,
         bounds: pathfinder_geometry::rect::RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &DebugContext,
+        cx: &ViewContext<V>,
     ) -> json::Value {
         json!({
             "type": "Align",
             "bounds": bounds.to_json(),
             "alignment": self.alignment.to_json(),
-            "child": self.child.debug(cx),
+            "child": self.child.debug(view, cx),
         })
     }
 }

crates/gpui/src/elements/canvas.rs 🔗

@@ -1,8 +1,7 @@
 use super::Element;
 use crate::{
     json::{self, json},
-    window::MeasurementContext,
-    DebugContext, PaintContext,
+    SceneBuilder, View, ViewContext,
 };
 use json::ToJson;
 use pathfinder_geometry::{
@@ -10,20 +9,20 @@ use pathfinder_geometry::{
     vector::{vec2f, Vector2F},
 };
 
-pub struct Canvas<F>(F);
+pub struct Canvas<V, F>(F);
 
-impl<F> Canvas<F>
+impl<V: View, F> Canvas<V, F>
 where
-    F: FnMut(RectF, RectF, &mut PaintContext),
+    F: FnMut(&mut SceneBuilder, RectF, RectF, &mut V, &mut ViewContext<V>),
 {
     pub fn new(f: F) -> Self {
         Self(f)
     }
 }
 
-impl<F> Element for Canvas<F>
+impl<V, F> Element<V> for Canvas<V, F>
 where
-    F: FnMut(RectF, RectF, &mut PaintContext),
+    F: FnMut(RectF, RectF, &mut ViewContext<V>),
 {
     type LayoutState = ();
     type PaintState = ();
@@ -48,10 +47,12 @@ where
 
     fn paint(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
-        cx: &mut PaintContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         self.0(bounds, visible_bounds, cx)
     }
@@ -63,7 +64,8 @@ where
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        _: &MeasurementContext,
+        _: &V,
+        _: &ViewContext<V>,
     ) -> Option<RectF> {
         None
     }
@@ -73,7 +75,8 @@ where
         bounds: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        _: &DebugContext,
+        _: &V,
+        _: &ViewContext<V>,
     ) -> json::Value {
         json!({"type": "Canvas", "bounds": bounds.to_json()})
     }

crates/gpui/src/elements/clipped.rs 🔗

@@ -3,42 +3,43 @@ use std::ops::Range;
 use pathfinder_geometry::{rect::RectF, vector::Vector2F};
 use serde_json::json;
 
-use crate::{
-    json, DebugContext, Element, ElementBox, LayoutContext, MeasurementContext, PaintContext,
-    SizeConstraint,
-};
+use crate::{json, Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext};
 
-pub struct Clipped {
-    child: ElementBox,
+pub struct Clipped<V: View> {
+    child: ElementBox<V>,
 }
 
-impl Clipped {
-    pub fn new(child: ElementBox) -> Self {
+impl<V: View> Clipped<V> {
+    pub fn new(child: ElementBox<V>) -> Self {
         Self { child }
     }
 }
 
-impl Element for Clipped {
+impl<V: View> Element<V> for Clipped<V> {
     type LayoutState = ();
     type PaintState = ();
 
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        cx: &mut LayoutContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
-        (self.child.layout(constraint, cx), ())
+        (self.child.layout(constraint, view, cx), ())
     }
 
     fn paint(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
-        cx: &mut PaintContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         cx.scene.push_layer(Some(bounds));
-        self.child.paint(bounds.origin(), visible_bounds, cx);
+        self.child
+            .paint(scene, bounds.origin(), visible_bounds, view, cx);
         cx.scene.pop_layer();
     }
 
@@ -49,9 +50,10 @@ impl Element for Clipped {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &MeasurementContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> Option<RectF> {
-        self.child.rect_for_text_range(range_utf16, cx)
+        self.child.rect_for_text_range(range_utf16, view, cx)
     }
 
     fn debug(
@@ -59,11 +61,12 @@ impl Element for Clipped {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &DebugContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> json::Value {
         json!({
             "type": "Clipped",
-            "child": self.child.debug(cx)
+            "child": self.child.debug(view, cx)
         })
     }
 }

crates/gpui/src/elements/constrained_box.rs 🔗

@@ -5,22 +5,20 @@ use serde_json::json;
 
 use crate::{
     geometry::{rect::RectF, vector::Vector2F},
-    json,
-    window::MeasurementContext,
-    DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
+    json, Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext,
 };
 
-pub struct ConstrainedBox {
-    child: ElementBox,
-    constraint: Constraint,
+pub struct ConstrainedBox<V: View> {
+    child: ElementBox<V>,
+    constraint: Constraint<V>,
 }
 
-pub enum Constraint {
+pub enum Constraint<V: View> {
     Static(SizeConstraint),
-    Dynamic(Box<dyn FnMut(SizeConstraint, &mut LayoutContext) -> SizeConstraint>),
+    Dynamic(Box<dyn FnMut(SizeConstraint, &mut V, &mut ViewContext<V>) -> SizeConstraint>),
 }
 
-impl ToJson for Constraint {
+impl<V: View> ToJson for Constraint<V> {
     fn to_json(&self) -> serde_json::Value {
         match self {
             Constraint::Static(constraint) => constraint.to_json(),
@@ -29,8 +27,8 @@ impl ToJson for Constraint {
     }
 }
 
-impl ConstrainedBox {
-    pub fn new(child: ElementBox) -> Self {
+impl<V: View> ConstrainedBox<V> {
+    pub fn new(child: ElementBox<V>) -> Self {
         Self {
             child,
             constraint: Constraint::Static(Default::default()),
@@ -39,7 +37,7 @@ impl ConstrainedBox {
 
     pub fn dynamically(
         mut self,
-        constraint: impl 'static + FnMut(SizeConstraint, &mut LayoutContext) -> SizeConstraint,
+        constraint: impl 'static + FnMut(SizeConstraint, &mut V, &mut ViewContext<V>) -> SizeConstraint,
     ) -> Self {
         self.constraint = Constraint::Dynamic(Box::new(constraint));
         self
@@ -120,41 +118,48 @@ impl ConstrainedBox {
     fn constraint(
         &mut self,
         input_constraint: SizeConstraint,
-        cx: &mut LayoutContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> SizeConstraint {
         match &mut self.constraint {
             Constraint::Static(constraint) => *constraint,
-            Constraint::Dynamic(compute_constraint) => compute_constraint(input_constraint, cx),
+            Constraint::Dynamic(compute_constraint) => {
+                compute_constraint(input_constraint, view, cx)
+            }
         }
     }
 }
 
-impl Element for ConstrainedBox {
+impl<V: View> Element<V> for ConstrainedBox<V> {
     type LayoutState = ();
     type PaintState = ();
 
     fn layout(
         &mut self,
         mut parent_constraint: SizeConstraint,
-        cx: &mut LayoutContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
-        let constraint = self.constraint(parent_constraint, cx);
+        let constraint = self.constraint(parent_constraint, view, cx);
         parent_constraint.min = parent_constraint.min.max(constraint.min);
         parent_constraint.max = parent_constraint.max.min(constraint.max);
         parent_constraint.max = parent_constraint.max.max(parent_constraint.min);
-        let size = self.child.layout(parent_constraint, cx);
+        let size = self.child.layout(parent_constraint, view, cx);
         (size, ())
     }
 
     fn paint(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
-        cx: &mut PaintContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         cx.paint_layer(Some(visible_bounds), |cx| {
-            self.child.paint(bounds.origin(), visible_bounds, cx);
+            self.child
+                .paint(scene, bounds.origin(), visible_bounds, view, cx);
         })
     }
 
@@ -165,9 +170,10 @@ impl Element for ConstrainedBox {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &MeasurementContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> Option<RectF> {
-        self.child.rect_for_text_range(range_utf16, cx)
+        self.child.rect_for_text_range(range_utf16, view, cx)
     }
 
     fn debug(
@@ -175,8 +181,9 @@ impl Element for ConstrainedBox {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &DebugContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> json::Value {
-        json!({"type": "ConstrainedBox", "assigned_constraint": self.constraint.to_json(), "child": self.child.debug(cx)})
+        json!({"type": "ConstrainedBox", "assigned_constraint": self.constraint.to_json(), "child": self.child.debug(view, cx)})
     }
 }

crates/gpui/src/elements/container.rs 🔗

@@ -10,8 +10,7 @@ use crate::{
     json::ToJson,
     platform::CursorStyle,
     scene::{self, Border, CursorRegion, Quad},
-    window::MeasurementContext,
-    Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
+    Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext,
 };
 use serde::Deserialize;
 use serde_json::json;
@@ -36,13 +35,13 @@ pub struct ContainerStyle {
     pub cursor: Option<CursorStyle>,
 }
 
-pub struct Container {
-    child: ElementBox,
+pub struct Container<V: View> {
+    child: ElementBox<V>,
     style: ContainerStyle,
 }
 
-impl Container {
-    pub fn new(child: ElementBox) -> Self {
+impl<V: View> Container<V> {
+    pub fn new(child: ElementBox<V>) -> Self {
         Self {
             child,
             style: Default::default(),
@@ -185,14 +184,15 @@ impl Container {
     }
 }
 
-impl Element for Container {
+impl<V: View> Element<V> for Container<V> {
     type LayoutState = ();
     type PaintState = ();
 
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        cx: &mut LayoutContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         let mut size_buffer = self.margin_size() + self.padding_size();
         if !self.style.border.overlay {
@@ -202,16 +202,18 @@ impl Element for Container {
             min: (constraint.min - size_buffer).max(Vector2F::zero()),
             max: (constraint.max - size_buffer).max(Vector2F::zero()),
         };
-        let child_size = self.child.layout(child_constraint, cx);
+        let child_size = self.child.layout(child_constraint, view, cx);
         (child_size + size_buffer, ())
     }
 
     fn paint(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
-        cx: &mut PaintContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         let quad_bounds = RectF::from_points(
             bounds.origin() + vec2f(self.style.margin.left, self.style.margin.top),
@@ -247,7 +249,8 @@ impl Element for Container {
                 corner_radius: self.style.corner_radius,
             });
 
-            self.child.paint(child_origin, visible_bounds, cx);
+            self.child
+                .paint(scene, child_origin, visible_bounds, view, cx);
 
             cx.scene.push_layer(None);
             cx.scene.push_quad(Quad {
@@ -270,7 +273,8 @@ impl Element for Container {
                     self.style.border.left_width(),
                     self.style.border.top_width(),
                 );
-            self.child.paint(child_origin, visible_bounds, cx);
+            self.child
+                .paint(scene, child_origin, visible_bounds, view, cx);
 
             if self.style.overlay_color.is_some() {
                 cx.scene.push_layer(None);
@@ -292,9 +296,10 @@ impl Element for Container {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &MeasurementContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> Option<RectF> {
-        self.child.rect_for_text_range(range_utf16, cx)
+        self.child.rect_for_text_range(range_utf16, view, cx)
     }
 
     fn debug(
@@ -302,13 +307,14 @@ impl Element for Container {
         bounds: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
+        view: &V,
         cx: &crate::DebugContext,
     ) -> serde_json::Value {
         json!({
             "type": "Container",
             "bounds": bounds.to_json(),
             "details": self.style.to_json(),
-            "child": self.child.debug(cx),
+            "child": self.child.debug(view, cx),
         })
     }
 }

crates/gpui/src/elements/empty.rs 🔗

@@ -6,10 +6,9 @@ use crate::{
         vector::{vec2f, Vector2F},
     },
     json::{json, ToJson},
-    window::MeasurementContext,
-    DebugContext,
+    SceneBuilder, View, ViewContext,
 };
-use crate::{Element, LayoutContext, PaintContext, SizeConstraint};
+use crate::{Element, SizeConstraint};
 
 #[derive(Default)]
 pub struct Empty {
@@ -27,14 +26,15 @@ impl Empty {
     }
 }
 
-impl Element for Empty {
+impl<V: View> Element<V> for Empty {
     type LayoutState = ();
     type PaintState = ();
 
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        _: &mut LayoutContext,
+        _: &V,
+        _: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         let x = if constraint.max.x().is_finite() && !self.collapsed {
             constraint.max.x()
@@ -52,10 +52,11 @@ impl Element for Empty {
 
     fn paint(
         &mut self,
+        _: &mut SceneBuilder,
         _: RectF,
         _: RectF,
         _: &mut Self::LayoutState,
-        _: &mut PaintContext,
+        _: &mut ViewContext<V>,
     ) -> Self::PaintState {
     }
 
@@ -66,7 +67,8 @@ impl Element for Empty {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        _: &MeasurementContext,
+        _: &V,
+        _: &ViewContext<V>,
     ) -> Option<RectF> {
         None
     }
@@ -76,7 +78,8 @@ impl Element for Empty {
         bounds: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        _: &DebugContext,
+        _: &V,
+        _: &ViewContext<V>,
     ) -> serde_json::Value {
         json!({
             "type": "Empty",

crates/gpui/src/elements/expanded.rs 🔗

@@ -2,20 +2,18 @@ use std::ops::Range;
 
 use crate::{
     geometry::{rect::RectF, vector::Vector2F},
-    json,
-    window::MeasurementContext,
-    DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
+    json, Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext,
 };
 use serde_json::json;
 
-pub struct Expanded {
-    child: ElementBox,
+pub struct Expanded<V: View> {
+    child: ElementBox<V>,
     full_width: bool,
     full_height: bool,
 }
 
-impl Expanded {
-    pub fn new(child: ElementBox) -> Self {
+impl<V: View> Expanded<V> {
+    pub fn new(child: ElementBox<V>) -> Self {
         Self {
             child,
             full_width: true,
@@ -36,14 +34,15 @@ impl Expanded {
     }
 }
 
-impl Element for Expanded {
+impl<V: View> Element<V> for Expanded<V> {
     type LayoutState = ();
     type PaintState = ();
 
     fn layout(
         &mut self,
         mut constraint: SizeConstraint,
-        cx: &mut LayoutContext,
+        view: &mut V,
+        cx: &mut ViewContext<Self>,
     ) -> (Vector2F, Self::LayoutState) {
         if self.full_width {
             constraint.min.set_x(constraint.max.x());
@@ -51,18 +50,21 @@ impl Element for Expanded {
         if self.full_height {
             constraint.min.set_y(constraint.max.y());
         }
-        let size = self.child.layout(constraint, cx);
+        let size = self.child.layout(constraint, view, cx);
         (size, ())
     }
 
     fn paint(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
-        cx: &mut PaintContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
-        self.child.paint(bounds.origin(), visible_bounds, cx);
+        self.child
+            .paint(scene, bounds.origin(), visible_bounds, view, cx);
     }
 
     fn rect_for_text_range(
@@ -72,9 +74,10 @@ impl Element for Expanded {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &MeasurementContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> Option<RectF> {
-        self.child.rect_for_text_range(range_utf16, cx)
+        self.child.rect_for_text_range(range_utf16, view, cx)
     }
 
     fn debug(
@@ -82,13 +85,14 @@ impl Element for Expanded {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &DebugContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> json::Value {
         json!({
             "type": "Expanded",
             "full_width": self.full_width,
             "full_height": self.full_height,
-            "child": self.child.debug(cx)
+            "child": self.child.debug(view, cx)
         })
     }
 }

crates/gpui/src/elements/flex.rs 🔗

@@ -2,9 +2,8 @@ use std::{any::Any, cell::Cell, f32::INFINITY, ops::Range, rc::Rc};
 
 use crate::{
     json::{self, ToJson, Value},
-    window::MeasurementContext,
-    Axis, DebugContext, Element, ElementBox, ElementStateHandle, LayoutContext, PaintContext,
-    RenderContext, SizeConstraint, Vector2FExt, View,
+    Axis, Element, ElementBox, ElementStateHandle, SceneBuilder, SizeConstraint, Vector2FExt, View,
+    ViewContext,
 };
 use pathfinder_geometry::{
     rect::RectF,
@@ -18,14 +17,14 @@ struct ScrollState {
     scroll_position: Cell<f32>,
 }
 
-pub struct Flex {
+pub struct Flex<V: View> {
     axis: Axis,
-    children: Vec<ElementBox>,
+    children: Vec<ElementBox<V>>,
     scroll_state: Option<(ElementStateHandle<Rc<ScrollState>>, usize)>,
     child_alignment: f32,
 }
 
-impl Flex {
+impl<V: View> Flex<V> {
     pub fn new(axis: Axis) -> Self {
         Self {
             axis,
@@ -52,15 +51,14 @@ impl Flex {
         self
     }
 
-    pub fn scrollable<Tag, V>(
+    pub fn scrollable<Tag>(
         mut self,
         element_id: usize,
         scroll_to: Option<usize>,
-        cx: &mut RenderContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self
     where
         Tag: 'static,
-        V: View,
     {
         let scroll_state = cx.default_element_state::<Tag, Rc<ScrollState>>(element_id);
         scroll_state.read(cx).scroll_to.set(scroll_to);
@@ -75,7 +73,8 @@ impl Flex {
         remaining_space: &mut f32,
         remaining_flex: &mut f32,
         cross_axis_max: &mut f32,
-        cx: &mut LayoutContext,
+        view: &V,
+        cx: &mut ViewContext<V>,
     ) {
         let cross_axis = self.axis.invert();
         for child in &mut self.children {
@@ -112,20 +111,21 @@ impl Flex {
     }
 }
 
-impl Extend<ElementBox> for Flex {
-    fn extend<T: IntoIterator<Item = ElementBox>>(&mut self, children: T) {
+impl<V: View> Extend<ElementBox<V>> for Flex<V> {
+    fn extend<T: IntoIterator<Item = ElementBox<V>>>(&mut self, children: T) {
         self.children.extend(children);
     }
 }
 
-impl Element for Flex {
+impl<V: View> Element<V> for Flex<V> {
     type LayoutState = f32;
     type PaintState = ();
 
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        cx: &mut LayoutContext,
+        view: &V,
+        cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         let mut total_flex = None;
         let mut fixed_space = 0.0;
@@ -150,7 +150,7 @@ impl Element for Flex {
                         vec2f(constraint.max.x(), INFINITY),
                     ),
                 };
-                let size = child.layout(child_constraint, cx);
+                let size = child.layout(child_constraint, view, cx);
                 fixed_space += size.along(self.axis);
                 cross_axis_max = cross_axis_max.max(size.along(cross_axis));
             }
@@ -168,6 +168,7 @@ impl Element for Flex {
                 &mut remaining_space,
                 &mut remaining_flex,
                 &mut cross_axis_max,
+                view,
                 cx,
             );
             self.layout_flex_children(
@@ -176,6 +177,7 @@ impl Element for Flex {
                 &mut remaining_space,
                 &mut remaining_flex,
                 &mut cross_axis_max,
+                view,
                 cx,
             );
 
@@ -247,10 +249,12 @@ impl Element for Flex {
 
     fn paint(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         remaining_space: &mut Self::LayoutState,
-        cx: &mut PaintContext,
+        view: &V,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
 
@@ -343,7 +347,7 @@ impl Element for Flex {
                 aligned_child_origin
             };
 
-            child.paint(aligned_child_origin, visible_bounds, cx);
+            child.paint(scene, aligned_child_origin, visible_bounds, view, cx);
 
             match self.axis {
                 Axis::Horizontal => child_origin += vec2f(child.size().x(), 0.0),
@@ -363,11 +367,12 @@ impl Element for Flex {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &MeasurementContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> Option<RectF> {
         self.children
             .iter()
-            .find_map(|child| child.rect_for_text_range(range_utf16.clone(), cx))
+            .find_map(|child| child.rect_for_text_range(view, range_utf16.clone(), cx))
     }
 
     fn debug(
@@ -375,13 +380,14 @@ impl Element for Flex {
         bounds: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &DebugContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> json::Value {
         json!({
             "type": "Flex",
             "bounds": bounds.to_json(),
             "axis": self.axis.to_json(),
-            "children": self.children.iter().map(|child| child.debug(cx)).collect::<Vec<json::Value>>()
+            "children": self.children.iter().map(|child| child.debug(view, cx)).collect::<Vec<json::Value>>()
         })
     }
 }
@@ -391,13 +397,13 @@ struct FlexParentData {
     float: bool,
 }
 
-pub struct FlexItem {
+pub struct FlexItem<V: View> {
     metadata: FlexParentData,
-    child: ElementBox,
+    child: ElementBox<V>,
 }
 
-impl FlexItem {
-    pub fn new(child: ElementBox) -> Self {
+impl<V: View> FlexItem<V> {
+    pub fn new(child: ElementBox<V>) -> Self {
         FlexItem {
             metadata: FlexParentData {
                 flex: None,
@@ -418,14 +424,15 @@ impl FlexItem {
     }
 }
 
-impl Element for FlexItem {
+impl<V: View> Element<V> for FlexItem<V> {
     type LayoutState = ();
     type PaintState = ();
 
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        cx: &mut LayoutContext,
+        view: &V,
+        cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         let size = self.child.layout(constraint, cx);
         (size, ())
@@ -433,12 +440,15 @@ impl Element for FlexItem {
 
     fn paint(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
+        view: &V,
         cx: &mut PaintContext,
     ) -> Self::PaintState {
-        self.child.paint(bounds.origin(), visible_bounds, cx)
+        self.child
+            .paint(scene, bounds.origin(), visible_bounds, view, cx)
     }
 
     fn rect_for_text_range(
@@ -448,9 +458,10 @@ impl Element for FlexItem {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &MeasurementContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> Option<RectF> {
-        self.child.rect_for_text_range(range_utf16, cx)
+        self.child.rect_for_text_range(range_utf16, view, cx)
     }
 
     fn metadata(&self) -> Option<&dyn Any> {
@@ -462,12 +473,14 @@ impl Element for FlexItem {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &DebugContext,
+        view: &V,
+
+        cx: &ViewContext<V>,
     ) -> Value {
         json!({
             "type": "Flexible",
             "flex": self.metadata.flex,
-            "child": self.child.debug(cx)
+            "child": self.child.debug(view, cx)
         })
     }
 }

crates/gpui/src/elements/hook.rs 🔗

@@ -3,17 +3,16 @@ use std::ops::Range;
 use crate::{
     geometry::{rect::RectF, vector::Vector2F},
     json::json,
-    window::MeasurementContext,
-    DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
+    Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext,
 };
 
-pub struct Hook {
-    child: ElementBox,
-    after_layout: Option<Box<dyn FnMut(Vector2F, &mut LayoutContext)>>,
+pub struct Hook<V: View> {
+    child: ElementBox<V>,
+    after_layout: Option<Box<dyn FnMut(Vector2F, &mut ViewContext<V>)>>,
 }
 
-impl Hook {
-    pub fn new(child: ElementBox) -> Self {
+impl<V: View> Hook<V> {
+    pub fn new(child: ElementBox<V>) -> Self {
         Self {
             child,
             after_layout: None,
@@ -22,23 +21,24 @@ impl Hook {
 
     pub fn on_after_layout(
         mut self,
-        f: impl 'static + FnMut(Vector2F, &mut LayoutContext),
+        f: impl 'static + FnMut(Vector2F, &mut ViewContext<V>),
     ) -> Self {
         self.after_layout = Some(Box::new(f));
         self
     }
 }
 
-impl Element for Hook {
+impl<V: View> Element<V> for Hook<V> {
     type LayoutState = ();
     type PaintState = ();
 
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        cx: &mut LayoutContext,
+        view: &V,
+        cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
-        let size = self.child.layout(constraint, cx);
+        let size = self.child.layout(constraint, view, cx);
         if let Some(handler) = self.after_layout.as_mut() {
             handler(size, cx);
         }
@@ -47,12 +47,15 @@ impl Element for Hook {
 
     fn paint(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
-        cx: &mut PaintContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) {
-        self.child.paint(bounds.origin(), visible_bounds, cx);
+        self.child
+            .paint(scene, bounds.origin(), visible_bounds, view, cx);
     }
 
     fn rect_for_text_range(
@@ -62,9 +65,10 @@ impl Element for Hook {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &MeasurementContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> Option<RectF> {
-        self.child.rect_for_text_range(range_utf16, cx)
+        self.child.rect_for_text_range(range_utf16, view, cx)
     }
 
     fn debug(
@@ -72,11 +76,12 @@ impl Element for Hook {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &DebugContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> serde_json::Value {
         json!({
             "type": "Hooks",
-            "child": self.child.debug(cx),
+            "child": self.child.debug(view, cx),
         })
     }
 }

crates/gpui/src/elements/image.rs 🔗

@@ -5,9 +5,7 @@ use crate::{
         vector::{vec2f, Vector2F},
     },
     json::{json, ToJson},
-    scene,
-    window::MeasurementContext,
-    Border, DebugContext, Element, ImageData, LayoutContext, PaintContext, SizeConstraint,
+    scene, Border, Element, ImageData, SceneBuilder, SizeConstraint, View, ViewContext,
 };
 use serde::Deserialize;
 use std::{ops::Range, sync::Arc};
@@ -57,14 +55,15 @@ impl Image {
     }
 }
 
-impl Element for Image {
+impl<V: View> Element<V> for Image {
     type LayoutState = Option<Arc<ImageData>>;
     type PaintState = ();
 
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        cx: &mut LayoutContext,
+        view: &V,
+        cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         let data = match &self.source {
             ImageSource::Path(path) => match cx.asset_cache.png(path) {
@@ -91,13 +90,15 @@ impl Element for Image {
 
     fn paint(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         _: RectF,
         layout: &mut Self::LayoutState,
-        cx: &mut PaintContext,
+        _: &V,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         if let Some(data) = layout {
-            cx.scene.push_image(scene::Image {
+            scene.push_image(scene::Image {
                 bounds,
                 border: self.style.border,
                 corner_radius: self.style.corner_radius,
@@ -114,7 +115,8 @@ impl Element for Image {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        _: &MeasurementContext,
+        _: &V,
+        _: &ViewContext<V>,
     ) -> Option<RectF> {
         None
     }
@@ -124,7 +126,8 @@ impl Element for Image {
         bounds: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        _: &DebugContext,
+        _: &V,
+        _: &ViewContext<V>,
     ) -> serde_json::Value {
         json!({
             "type": "Image",

crates/gpui/src/elements/keystroke_label.rs 🔗

@@ -2,7 +2,7 @@ use crate::{
     elements::*,
     fonts::TextStyle,
     geometry::{rect::RectF, vector::Vector2F},
-    Action, ElementBox, LayoutContext, PaintContext, SizeConstraint,
+    Action, ElementBox, SizeConstraint,
 };
 use serde_json::json;
 
@@ -34,15 +34,16 @@ impl KeystrokeLabel {
     }
 }
 
-impl Element for KeystrokeLabel {
-    type LayoutState = ElementBox;
+impl<V: View> Element<V> for KeystrokeLabel {
+    type LayoutState = ElementBox<V>;
     type PaintState = ();
 
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        cx: &mut LayoutContext,
-    ) -> (Vector2F, ElementBox) {
+        view: &V,
+        cx: &mut ViewContext<V>,
+    ) -> (Vector2F, ElementBox<V>) {
         let mut element = if let Some(keystrokes) =
             cx.app
                 .keystrokes_for_action(self.window_id, self.view_id, self.action.as_ref())
@@ -59,18 +60,20 @@ impl Element for KeystrokeLabel {
             Empty::new().collapsed().boxed()
         };
 
-        let size = element.layout(constraint, cx);
+        let size = element.layout(constraint, view, cx);
         (size, element)
     }
 
     fn paint(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
-        element: &mut ElementBox,
-        cx: &mut PaintContext,
+        element: &mut ElementBox<V>,
+        view: &V,
+        cx: &mut ViewContext<V>,
     ) {
-        element.paint(bounds.origin(), visible_bounds, cx);
+        element.paint(scene, bounds.origin(), visible_bounds, view, cx);
     }
 
     fn rect_for_text_range(
@@ -80,7 +83,8 @@ impl Element for KeystrokeLabel {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        _: &MeasurementContext,
+        _: &V,
+        _: &ViewContext<V>,
     ) -> Option<RectF> {
         None
     }
@@ -88,14 +92,15 @@ impl Element for KeystrokeLabel {
     fn debug(
         &self,
         _: RectF,
-        element: &ElementBox,
+        element: &ElementBox<V>,
         _: &(),
-        cx: &crate::DebugContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> serde_json::Value {
         json!({
             "type": "KeystrokeLabel",
             "action": self.action.name(),
-            "child": element.debug(cx)
+            "child": element.debug(view, cx)
         })
     }
 }

crates/gpui/src/elements/label.rs 🔗

@@ -8,8 +8,7 @@ use crate::{
     },
     json::{ToJson, Value},
     text_layout::{Line, RunStyle},
-    window::MeasurementContext,
-    DebugContext, Element, LayoutContext, PaintContext, SizeConstraint,
+    Element, SceneBuilder, SizeConstraint, View, ViewContext,
 };
 use serde::Deserialize;
 use serde_json::json;
@@ -128,14 +127,15 @@ impl Label {
     }
 }
 
-impl Element for Label {
+impl<V: View> Element<V> for Label {
     type LayoutState = Line;
     type PaintState = ();
 
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        cx: &mut LayoutContext,
+        view: &V,
+        cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         let runs = self.compute_runs();
         let line =
@@ -155,12 +155,20 @@ impl Element for Label {
 
     fn paint(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         line: &mut Self::LayoutState,
-        cx: &mut PaintContext,
+        _: &V,
+        cx: &mut ViewContext<Self>,
     ) -> Self::PaintState {
-        line.paint(bounds.origin(), visible_bounds, bounds.size().y(), cx)
+        line.paint(
+            scene,
+            bounds.origin(),
+            visible_bounds,
+            bounds.size().y(),
+            cx,
+        )
     }
 
     fn rect_for_text_range(
@@ -170,7 +178,8 @@ impl Element for Label {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        _: &MeasurementContext,
+        _: &V,
+        _: &ViewContext<V>,
     ) -> Option<RectF> {
         None
     }
@@ -180,7 +189,8 @@ impl Element for Label {
         bounds: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        _: &DebugContext,
+        _: &V,
+        _: &ViewContext<V>,
     ) -> Value {
         json!({
             "type": "Label",

crates/gpui/src/elements/list.rs 🔗

@@ -4,19 +4,17 @@ use crate::{
         vector::{vec2f, Vector2F},
     },
     json::json,
-    window::MeasurementContext,
-    DebugContext, Element, ElementBox, ElementRc, EventContext, LayoutContext, MouseRegion,
-    PaintContext, RenderContext, SizeConstraint, View, ViewContext,
+    Element, ElementBox, MouseRegion, SceneBuilder, SizeConstraint, View, ViewContext,
 };
 use std::{cell::RefCell, collections::VecDeque, ops::Range, rc::Rc};
 use sum_tree::{Bias, SumTree};
 
-pub struct List {
-    state: ListState,
+pub struct List<V: View> {
+    state: ListState<V>,
 }
 
 #[derive(Clone)]
-pub struct ListState(Rc<RefCell<StateInner>>);
+pub struct ListState<V: View>(Rc<RefCell<StateInner<V>>>);
 
 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 pub enum Orientation {
@@ -24,16 +22,16 @@ pub enum Orientation {
     Bottom,
 }
 
-struct StateInner {
+struct StateInner<V: View> {
     last_layout_width: Option<f32>,
-    render_item: Box<dyn FnMut(usize, &mut LayoutContext) -> Option<ElementBox>>,
+    render_item: Box<dyn FnMut(usize, &V, &mut ViewContext<V>) -> Option<ElementBox<V>>>,
     rendered_range: Range<usize>,
-    items: SumTree<ListItem>,
+    items: SumTree<ListItem<V>>,
     logical_scroll_top: Option<ListOffset>,
     orientation: Orientation,
     overdraw: f32,
     #[allow(clippy::type_complexity)]
-    scroll_handler: Option<Box<dyn FnMut(Range<usize>, &mut EventContext)>>,
+    scroll_handler: Option<Box<dyn FnMut(Range<usize>, &mut V, &mut ViewContext<V>)>>,
 }
 
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
@@ -43,13 +41,13 @@ pub struct ListOffset {
 }
 
 #[derive(Clone)]
-enum ListItem {
+enum ListItem<V: View> {
     Unrendered,
-    Rendered(ElementRc),
+    Rendered(Rc<ElementBox<V>>),
     Removed(f32),
 }
 
-impl std::fmt::Debug for ListItem {
+impl<V: View> std::fmt::Debug for ListItem<V> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
             Self::Unrendered => write!(f, "Unrendered"),
@@ -79,20 +77,21 @@ struct UnrenderedCount(usize);
 #[derive(Clone, Debug, Default)]
 struct Height(f32);
 
-impl List {
-    pub fn new(state: ListState) -> Self {
+impl<V: View> List<V> {
+    pub fn new(state: ListState<V>) -> Self {
         Self { state }
     }
 }
 
-impl Element for List {
+impl<V: View> Element<V> for List<V> {
     type LayoutState = ListOffset;
     type PaintState = ();
 
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        cx: &mut LayoutContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         let state = &mut *self.state.0.borrow_mut();
         let size = constraint.max;
@@ -134,6 +133,7 @@ impl Element for List {
                 scroll_top.item_ix + ix,
                 existing_element,
                 item_constraint,
+                view,
                 cx,
             ) {
                 rendered_height += element.size().y();
@@ -151,7 +151,7 @@ impl Element for List {
                 cursor.prev(&());
                 if cursor.item().is_some() {
                     if let Some(element) =
-                        state.render_item(cursor.start().0, None, item_constraint, cx)
+                        state.render_item(cursor.start().0, None, item_constraint, view, cx)
                     {
                         rendered_height += element.size().y();
                         rendered_items.push_front(ListItem::Rendered(element));
@@ -187,7 +187,7 @@ impl Element for List {
             cursor.prev(&());
             if let Some(item) = cursor.item() {
                 if let Some(element) =
-                    state.render_item(cursor.start().0, Some(item), item_constraint, cx)
+                    state.render_item(cursor.start().0, Some(item), item_constraint, view, cx)
                 {
                     leading_overdraw += element.size().y();
                     rendered_items.push_front(ListItem::Rendered(element));
@@ -241,10 +241,12 @@ impl Element for List {
 
     fn paint(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         scroll_top: &mut ListOffset,
-        cx: &mut PaintContext,
+        view: &V,
+        cx: &mut ViewContext<V>,
     ) {
         let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default();
         cx.scene.push_layer(Some(visible_bounds));
@@ -268,7 +270,7 @@ impl Element for List {
 
         let state = &mut *self.state.0.borrow_mut();
         for (mut element, origin) in state.visible_elements(bounds, scroll_top) {
-            element.paint(origin, visible_bounds, cx);
+            element.paint(scene, origin, visible_bounds, view, cx);
         }
 
         cx.scene.pop_layer();
@@ -281,7 +283,8 @@ impl Element for List {
         _: RectF,
         scroll_top: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &MeasurementContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> Option<RectF> {
         let state = self.state.0.borrow();
         let mut item_origin = bounds.origin() - vec2f(0., scroll_top.offset_in_item);
@@ -293,7 +296,7 @@ impl Element for List {
             }
 
             if let ListItem::Rendered(element) = item {
-                if let Some(rect) = element.rect_for_text_range(range_utf16.clone(), cx) {
+                if let Some(rect) = element.rect_for_text_range(range_utf16.clone(), view, cx) {
                     return Some(rect);
                 }
 
@@ -312,12 +315,13 @@ impl Element for List {
         bounds: RectF,
         scroll_top: &Self::LayoutState,
         _: &(),
-        cx: &DebugContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> serde_json::Value {
         let state = self.state.0.borrow_mut();
         let visible_elements = state
             .visible_elements(bounds, scroll_top)
-            .map(|e| e.0.debug(cx))
+            .map(|e| e.0.debug(view, cx))
             .collect::<Vec<_>>();
         let visible_range = scroll_top.item_ix..(scroll_top.item_ix + visible_elements.len());
         json!({
@@ -328,8 +332,8 @@ impl Element for List {
     }
 }
 
-impl ListState {
-    pub fn new<F, V>(
+impl<V: View> ListState<V> {
+    pub fn new<F>(
         element_count: usize,
         orientation: Orientation,
         overdraw: f32,
@@ -338,7 +342,7 @@ impl ListState {
     ) -> Self
     where
         V: View,
-        F: 'static + FnMut(&mut V, usize, &mut RenderContext<V>) -> ElementBox,
+        F: 'static + FnMut(&mut V, usize, &mut ViewContext<V>) -> ElementBox<V>,
     {
         let mut items = SumTree::new();
         items.extend((0..element_count).map(|_| ListItem::Unrendered), &());
@@ -406,7 +410,7 @@ impl ListState {
 
     pub fn set_scroll_handler(
         &mut self,
-        handler: impl FnMut(Range<usize>, &mut EventContext) + 'static,
+        handler: impl FnMut(Range<usize>, &mut V, &mut ViewContext<V>) + 'static,
     ) {
         self.0.borrow_mut().scroll_handler = Some(Box::new(handler))
     }
@@ -426,14 +430,15 @@ impl ListState {
     }
 }
 
-impl StateInner {
+impl<V: View> StateInner<V> {
     fn render_item(
         &mut self,
         ix: usize,
-        existing_element: Option<&ListItem>,
+        existing_element: Option<&ListItem<V>>,
         constraint: SizeConstraint,
-        cx: &mut LayoutContext,
-    ) -> Option<ElementRc> {
+        view: &mut V,
+        cx: &mut ViewContext<V>,
+    ) -> Option<Rc<ElementBox<V>>> {
         if let Some(ListItem::Rendered(element)) = existing_element {
             Some(element.clone())
         } else {
@@ -455,7 +460,7 @@ impl StateInner {
         &'a self,
         bounds: RectF,
         scroll_top: &ListOffset,
-    ) -> impl Iterator<Item = (ElementRc, Vector2F)> + 'a {
+    ) -> impl Iterator<Item = (Rc<ElementBox>, Vector2F)> + 'a {
         let mut item_origin = bounds.origin() - vec2f(0., scroll_top.offset_in_item);
         let mut cursor = self.items.cursor::<Count>();
         cursor.seek(&Count(scroll_top.item_ix), Bias::Right, &());
@@ -485,7 +490,8 @@ impl StateInner {
         height: f32,
         mut delta: Vector2F,
         precise: bool,
-        cx: &mut EventContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) {
         if !precise {
             delta *= 20.;
@@ -538,7 +544,7 @@ impl StateInner {
     }
 }
 
-impl ListItem {
+impl<V: View> ListItem<V> {
     fn remove(&self) -> Self {
         match self {
             ListItem::Unrendered => ListItem::Unrendered,
@@ -548,7 +554,7 @@ impl ListItem {
     }
 }
 
-impl sum_tree::Item for ListItem {
+impl<V: View> sum_tree::Item for ListItem<V> {
     type Summary = ListItemSummary;
 
     fn summary(&self) -> Self::Summary {
@@ -900,7 +906,7 @@ mod tests {
             "TestView"
         }
 
-        fn render(&mut self, _: &mut RenderContext<'_, Self>) -> ElementBox {
+        fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox<Self> {
             Empty::new().boxed()
         }
     }
@@ -919,15 +925,28 @@ mod tests {
         }
     }
 
-    impl Element for TestElement {
+    impl<V: View> Element<V> for TestElement {
         type LayoutState = ();
         type PaintState = ();
 
-        fn layout(&mut self, _: SizeConstraint, _: &mut LayoutContext) -> (Vector2F, ()) {
+        fn layout(
+            &mut self,
+            _: SizeConstraint,
+            _: &mut V,
+            _: &mut ViewContext<V>,
+        ) -> (Vector2F, ()) {
             (self.size, ())
         }
 
-        fn paint(&mut self, _: RectF, _: RectF, _: &mut (), _: &mut PaintContext) {
+        fn paint(
+            &mut self,
+            _: &mut SceneBuilder,
+            _: RectF,
+            _: RectF,
+            _: &mut (),
+            _: &mut V,
+            _: &mut ViewContext<V>,
+        ) {
             todo!()
         }
 
@@ -938,12 +957,13 @@ mod tests {
             _: RectF,
             _: &Self::LayoutState,
             _: &Self::PaintState,
-            _: &MeasurementContext,
+            _: &V,
+            _: &ViewContext<V>,
         ) -> Option<RectF> {
             todo!()
         }
 
-        fn debug(&self, _: RectF, _: &(), _: &(), _: &DebugContext) -> serde_json::Value {
+        fn debug(&self, _: RectF, _: &(), _: &(), _: &V, _: &ViewContext<V>) -> serde_json::Value {
             self.id.into()
         }
 

crates/gpui/src/elements/mouse_event_handler.rs 🔗

@@ -10,14 +10,13 @@ use crate::{
         CursorRegion, HandlerSet, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseHover,
         MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut,
     },
-    DebugContext, Element, ElementBox, EventContext, LayoutContext, MeasurementContext,
-    MouseRegion, MouseState, PaintContext, RenderContext, SizeConstraint, View,
+    Element, ElementBox, MouseRegion, MouseState, SceneBuilder, SizeConstraint, View, ViewContext,
 };
 use serde_json::json;
 use std::{marker::PhantomData, ops::Range};
 
-pub struct MouseEventHandler<Tag: 'static> {
-    child: ElementBox,
+pub struct MouseEventHandler<Tag: 'static, V: View> {
+    child: ElementBox<V>,
     region_id: usize,
     cursor_style: Option<CursorStyle>,
     handlers: HandlerSet,
@@ -31,14 +30,14 @@ pub struct MouseEventHandler<Tag: 'static> {
 
 /// Element which provides a render_child callback with a MouseState and paints a mouse
 /// region under (or above) it for easy mouse event handling.
-impl<Tag> MouseEventHandler<Tag> {
-    pub fn new<V, F>(region_id: usize, cx: &mut RenderContext<V>, render_child: F) -> Self
+impl<Tag, V: View> MouseEventHandler<Tag, V> {
+    pub fn new<F>(region_id: usize, view: &mut V, cx: &mut ViewContext<V>, render_child: F) -> Self
     where
         V: View,
-        F: FnOnce(&mut MouseState, &mut RenderContext<V>) -> ElementBox,
+        F: FnOnce(&mut MouseState, &mut V, &mut ViewContext<V>) -> ElementBox<V>,
     {
         let mut mouse_state = cx.mouse_state::<Tag>(region_id);
-        let child = render_child(&mut mouse_state, cx);
+        let child = render_child(&mut mouse_state, view, cx);
         let notify_on_hover = mouse_state.accessed_hovered();
         let notify_on_click = mouse_state.accessed_clicked();
         Self {
@@ -58,12 +57,17 @@ impl<Tag> MouseEventHandler<Tag> {
     /// Modifies the MouseEventHandler to render the MouseRegion above the child element. Useful
     /// for drag and drop handling and similar events which should be captured before the child
     /// gets the opportunity
-    pub fn above<V, F>(region_id: usize, cx: &mut RenderContext<V>, render_child: F) -> Self
+    pub fn above<F>(
+        region_id: usize,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
+        render_child: F,
+    ) -> Self
     where
         V: View,
-        F: FnOnce(&mut MouseState, &mut RenderContext<V>) -> ElementBox,
+        F: FnOnce(&mut MouseState, &mut V, &mut ViewContext<V>) -> ElementBox<V>,
     {
-        let mut handler = Self::new(region_id, cx, render_child);
+        let mut handler = Self::new(region_id, view, cx, render_child);
         handler.above = true;
         handler
     }
@@ -78,14 +82,14 @@ impl<Tag> MouseEventHandler<Tag> {
         self
     }
 
-    pub fn on_move(mut self, handler: impl Fn(MouseMove, &mut EventContext) + 'static) -> Self {
+    pub fn on_move(mut self, handler: impl Fn(MouseMove, &mut ViewContext<V>) + 'static) -> Self {
         self.handlers = self.handlers.on_move(handler);
         self
     }
 
     pub fn on_move_out(
         mut self,
-        handler: impl Fn(MouseMoveOut, &mut EventContext) + 'static,
+        handler: impl Fn(MouseMoveOut, &mut ViewContext<V>) + 'static,
     ) -> Self {
         self.handlers = self.handlers.on_move_out(handler);
         self
@@ -94,7 +98,7 @@ impl<Tag> MouseEventHandler<Tag> {
     pub fn on_down(
         mut self,
         button: MouseButton,
-        handler: impl Fn(MouseDown, &mut EventContext) + 'static,
+        handler: impl Fn(MouseDown, &mut ViewContext<V>) + 'static,
     ) -> Self {
         self.handlers = self.handlers.on_down(button, handler);
         self
@@ -103,7 +107,7 @@ impl<Tag> MouseEventHandler<Tag> {
     pub fn on_up(
         mut self,
         button: MouseButton,
-        handler: impl Fn(MouseUp, &mut EventContext) + 'static,
+        handler: impl Fn(MouseUp, &mut ViewContext<V>) + 'static,
     ) -> Self {
         self.handlers = self.handlers.on_up(button, handler);
         self
@@ -112,7 +116,7 @@ impl<Tag> MouseEventHandler<Tag> {
     pub fn on_click(
         mut self,
         button: MouseButton,
-        handler: impl Fn(MouseClick, &mut EventContext) + 'static,
+        handler: impl Fn(MouseClick, &mut ViewContext<V>) + 'static,
     ) -> Self {
         self.handlers = self.handlers.on_click(button, handler);
         self
@@ -121,7 +125,7 @@ impl<Tag> MouseEventHandler<Tag> {
     pub fn on_down_out(
         mut self,
         button: MouseButton,
-        handler: impl Fn(MouseDownOut, &mut EventContext) + 'static,
+        handler: impl Fn(MouseDownOut, &mut ViewContext<V>) + 'static,
     ) -> Self {
         self.handlers = self.handlers.on_down_out(button, handler);
         self
@@ -130,7 +134,7 @@ impl<Tag> MouseEventHandler<Tag> {
     pub fn on_up_out(
         mut self,
         button: MouseButton,
-        handler: impl Fn(MouseUpOut, &mut EventContext) + 'static,
+        handler: impl Fn(MouseUpOut, &mut ViewContext<V>) + 'static,
     ) -> Self {
         self.handlers = self.handlers.on_up_out(button, handler);
         self
@@ -139,20 +143,20 @@ impl<Tag> MouseEventHandler<Tag> {
     pub fn on_drag(
         mut self,
         button: MouseButton,
-        handler: impl Fn(MouseDrag, &mut EventContext) + 'static,
+        handler: impl Fn(MouseDrag, &mut ViewContext<V>) + 'static,
     ) -> Self {
         self.handlers = self.handlers.on_drag(button, handler);
         self
     }
 
-    pub fn on_hover(mut self, handler: impl Fn(MouseHover, &mut EventContext) + 'static) -> Self {
+    pub fn on_hover(mut self, handler: impl Fn(MouseHover, &mut ViewContext<V>) + 'static) -> Self {
         self.handlers = self.handlers.on_hover(handler);
         self
     }
 
     pub fn on_scroll(
         mut self,
-        handler: impl Fn(MouseScrollWheel, &mut EventContext) + 'static,
+        handler: impl Fn(MouseScrollWheel, &mut ViewContext<V>) + 'static,
     ) -> Self {
         self.handlers = self.handlers.on_scroll(handler);
         self
@@ -176,7 +180,13 @@ impl<Tag> MouseEventHandler<Tag> {
         .round_out()
     }
 
-    fn paint_regions(&self, bounds: RectF, visible_bounds: RectF, cx: &mut PaintContext) {
+    fn paint_regions(
+        &self,
+        scene: &mut SceneBuilder,
+        bounds: RectF,
+        visible_bounds: RectF,
+        cx: &mut ViewContext<V>,
+    ) {
         let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default();
         let hit_bounds = self.hit_bounds(visible_bounds);
 
@@ -200,34 +210,37 @@ impl<Tag> MouseEventHandler<Tag> {
     }
 }
 
-impl<Tag> Element for MouseEventHandler<Tag> {
+impl<Tag, V: View> Element<V> for MouseEventHandler<Tag, V> {
     type LayoutState = ();
     type PaintState = ();
 
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        cx: &mut LayoutContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
-        (self.child.layout(constraint, cx), ())
+        (self.child.layout(constraint, view, cx), ())
     }
 
     fn paint(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
-        cx: &mut PaintContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         if self.above {
-            self.child.paint(bounds.origin(), visible_bounds, cx);
+            self.child.paint(bounds.origin(), visible_bounds, view, cx);
 
             cx.paint_layer(None, |cx| {
                 self.paint_regions(bounds, visible_bounds, cx);
             });
         } else {
             self.paint_regions(bounds, visible_bounds, cx);
-            self.child.paint(bounds.origin(), visible_bounds, cx);
+            self.child.paint(bounds.origin(), visible_bounds, view, cx);
         }
     }
 
@@ -238,9 +251,10 @@ impl<Tag> Element for MouseEventHandler<Tag> {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &MeasurementContext,
+        view: &V,
+        cx: &ViewContext<Self>,
     ) -> Option<RectF> {
-        self.child.rect_for_text_range(range_utf16, cx)
+        self.child.rect_for_text_range(range_utf16, view, cx)
     }
 
     fn debug(
@@ -248,11 +262,12 @@ impl<Tag> Element for MouseEventHandler<Tag> {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &DebugContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> serde_json::Value {
         json!({
             "type": "MouseEventHandler",
-            "child": self.child.debug(cx),
+            "child": self.child.debug(view, cx),
         })
     }
 }

crates/gpui/src/elements/overlay.rs 🔗

@@ -3,14 +3,12 @@ use std::ops::Range;
 use crate::{
     geometry::{rect::RectF, vector::Vector2F},
     json::ToJson,
-    window::MeasurementContext,
-    Axis, DebugContext, Element, ElementBox, LayoutContext, MouseRegion, PaintContext,
-    SizeConstraint,
+    Axis, Element, ElementBox, MouseRegion, SceneBuilder, SizeConstraint, View, ViewContext,
 };
 use serde_json::json;
 
-pub struct Overlay {
-    child: ElementBox,
+pub struct Overlay<V: View> {
+    child: ElementBox<V>,
     anchor_position: Option<Vector2F>,
     anchor_corner: AnchorCorner,
     fit_mode: OverlayFitMode,
@@ -74,8 +72,8 @@ impl AnchorCorner {
     }
 }
 
-impl Overlay {
-    pub fn new(child: ElementBox) -> Self {
+impl<V: View> Overlay<V> {
+    pub fn new(child: ElementBox<V>) -> Self {
         Self {
             child,
             anchor_position: None,
@@ -118,14 +116,15 @@ impl Overlay {
     }
 }
 
-impl Element for Overlay {
+impl<V: View> Element<V> for Overlay<V> {
     type LayoutState = Vector2F;
     type PaintState = ();
 
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        cx: &mut LayoutContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         let constraint = if self.anchor_position.is_some() {
             SizeConstraint::new(Vector2F::zero(), cx.window_size)
@@ -138,10 +137,12 @@ impl Element for Overlay {
 
     fn paint(
         &mut self,
+        scene: SceneBuilder,
         bounds: RectF,
         _: RectF,
         size: &mut Self::LayoutState,
-        cx: &mut PaintContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) {
         let (anchor_position, mut bounds) = match self.position_mode {
             OverlayPositionMode::Window => {
@@ -224,8 +225,10 @@ impl Element for Overlay {
             }
 
             self.child.paint(
+                scene,
                 bounds.origin(),
                 RectF::new(Vector2F::zero(), cx.window_size),
+                view,
                 cx,
             );
         });
@@ -238,9 +241,10 @@ impl Element for Overlay {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &MeasurementContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> Option<RectF> {
-        self.child.rect_for_text_range(range_utf16, cx)
+        self.child.rect_for_text_range(range_utf16, view, cx)
     }
 
     fn debug(
@@ -248,12 +252,13 @@ impl Element for Overlay {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &DebugContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> serde_json::Value {
         json!({
             "type": "Overlay",
             "abs_position": self.anchor_position.to_json(),
-            "child": self.child.debug(cx),
+            "child": self.child.debug(view, cx),
         })
     }
 }

crates/gpui/src/elements/uniform_list.rs 🔗

@@ -1,4 +1,4 @@
-use super::{Element, EventContext, LayoutContext, PaintContext, SizeConstraint};
+use super::{Element, SizeConstraint};
 use crate::{
     geometry::{
         rect::RectF,
@@ -7,8 +7,7 @@ use crate::{
     json::{self, json},
     platform::ScrollWheelEvent,
     scene::MouseScrollWheel,
-    window::MeasurementContext,
-    ElementBox, MouseRegion, RenderContext, View,
+    ElementBox, MouseRegion, SceneBuilder, View, ViewContext,
 };
 use json::ToJson;
 use std::{cell::RefCell, cmp, ops::Range, rc::Rc};
@@ -38,33 +37,33 @@ struct StateInner {
     scroll_to: Option<ScrollTarget>,
 }
 
-pub struct LayoutState {
+pub struct LayoutState<V: View> {
     scroll_max: f32,
     item_height: f32,
-    items: Vec<ElementBox>,
+    items: Vec<ElementBox<V>>,
 }
 
-pub struct UniformList {
+pub struct UniformList<V: View> {
     state: UniformListState,
     item_count: usize,
     #[allow(clippy::type_complexity)]
-    append_items: Box<dyn Fn(Range<usize>, &mut Vec<ElementBox>, &mut LayoutContext)>,
+    append_items: Box<dyn Fn(Range<usize>, &mut Vec<ElementBox<V>>, &mut V, &mut ViewContext<V>)>,
     padding_top: f32,
     padding_bottom: f32,
     get_width_from_item: Option<usize>,
     view_id: usize,
 }
 
-impl UniformList {
-    pub fn new<F, V>(
+impl<V: View> UniformList<V> {
+    pub fn new<F>(
         state: UniformListState,
         item_count: usize,
-        cx: &mut RenderContext<V>,
+        cx: &mut ViewContext<V>,
         append_items: F,
     ) -> Self
     where
         V: View,
-        F: 'static + Fn(&mut V, Range<usize>, &mut Vec<ElementBox>, &mut RenderContext<V>),
+        F: 'static + Fn(&mut V, Range<usize>, &mut Vec<ElementBox<V>>, &mut V, &mut ViewContext<V>),
     {
         let handle = cx.handle();
         Self {
@@ -160,14 +159,15 @@ impl UniformList {
     }
 }
 
-impl Element for UniformList {
-    type LayoutState = LayoutState;
+impl<V: View> Element<V> for UniformList<V> {
+    type LayoutState = LayoutState<V>;
     type PaintState = ();
 
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        cx: &mut LayoutContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         if constraint.max.y().is_infinite() {
             unimplemented!(
@@ -262,7 +262,7 @@ impl Element for UniformList {
         }
 
         for item in &mut items {
-            let item_size = item.layout(item_constraint, cx);
+            let item_size = item.layout(item_constraint, view, cx);
             if item_size.x() > size.x() {
                 size.set_x(item_size.x());
             }
@@ -280,10 +280,12 @@ impl Element for UniformList {
 
     fn paint(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         layout: &mut Self::LayoutState,
-        cx: &mut PaintContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default();
 
@@ -322,7 +324,7 @@ impl Element for UniformList {
             );
 
         for item in &mut layout.items {
-            item.paint(item_origin, visible_bounds, cx);
+            item.paint(scene, item_origin, visible_bounds, view, cx);
             item_origin += vec2f(0.0, layout.item_height);
         }
 
@@ -336,12 +338,13 @@ impl Element for UniformList {
         _: RectF,
         layout: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &MeasurementContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> Option<RectF> {
         layout
             .items
             .iter()
-            .find_map(|child| child.rect_for_text_range(range.clone(), cx))
+            .find_map(|child| child.rect_for_text_range(range.clone(), view, cx))
     }
 
     fn debug(
@@ -349,14 +352,15 @@ impl Element for UniformList {
         bounds: RectF,
         layout: &Self::LayoutState,
         _: &Self::PaintState,
-        cx: &crate::DebugContext,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> json::Value {
         json!({
             "type": "UniformList",
             "bounds": bounds.to_json(),
             "scroll_max": layout.scroll_max,
             "item_height": layout.item_height,
-            "items": layout.items.iter().map(|item| item.debug(cx)).collect::<Vec<json::Value>>()
+            "items": layout.items.iter().map(|item| item.debug(view, cx)).collect::<Vec<json::Value>>()
 
         })
     }

crates/gpui/src/text_layout.rs 🔗

@@ -7,7 +7,9 @@ use crate::{
     },
     platform,
     platform::FontSystem,
-    scene, PaintContext,
+    scene,
+    window::WindowContext,
+    AppContext, PaintContext, SceneBuilder,
 };
 use ordered_float::OrderedFloat;
 use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
@@ -271,10 +273,11 @@ impl Line {
 
     pub fn paint(
         &self,
+        scene: &SceneBuilder,
         origin: Vector2F,
         visible_bounds: RectF,
         line_height: f32,
-        cx: &mut PaintContext,
+        cx: &mut WindowContext,
     ) {
         let padding_top = (line_height - self.layout.ascent - self.layout.descent) / 2.;
         let baseline_offset = vec2f(0., padding_top + self.layout.ascent);

crates/search/src/project_search.rs 🔗

@@ -12,8 +12,8 @@ use gpui::{
     actions,
     elements::*,
     platform::{CursorStyle, MouseButton},
-    Action, AnyViewHandle, AppContext, ElementBox, Entity, ModelContext, ModelHandle,
-    RenderContext, Subscription, Task, View, ViewContext, ViewHandle, WeakModelHandle,
+    Action, AnyViewHandle, AppContext, Entity, ModelContext, ModelHandle, RenderContext,
+    Subscription, Task, View, ViewContext, ElementBox, ViewHandle, WeakModelHandle,
     WeakViewHandle,
 };
 use menu::Confirm;

crates/theme_testbench/src/theme_testbench.rs 🔗

@@ -2,8 +2,8 @@ use gpui::{
     actions,
     color::Color,
     elements::{
-        Canvas, Container, ContainerStyle, ElementBox, Flex, Label, Margin, MouseEventHandler,
-        Padding, ParentElement,
+        Canvas, Container, ContainerStyle, Flex, Label, Margin, MouseEventHandler, Padding,
+        ParentElement, ElementBox,
     },
     fonts::TextStyle,
     AppContext, Border, Element, Entity, ModelHandle, Quad, RenderContext, Task, View, ViewContext,

crates/workspace/src/toolbar.rs 🔗

@@ -1,7 +1,7 @@
 use crate::{ItemHandle, Pane};
 use gpui::{
     elements::*, platform::CursorStyle, platform::MouseButton, Action, AnyViewHandle, AppContext,
-    ElementBox, Entity, RenderContext, View, ViewContext, ViewHandle, WeakViewHandle,
+    Entity, RenderContext, View, ViewContext, ElementBox, ViewHandle, WeakViewHandle,
 };
 use settings::Settings;