Eliminate PaintContext

Nathan Sobo created

Change summary

crates/collab_ui/src/collab_titlebar_item.rs    |  6 
crates/collab_ui/src/face_pile.rs               |  4 
crates/editor/src/element.rs                    | 20 +--
crates/gpui/examples/corner_radii.rs            |  2 
crates/gpui/src/app.rs                          | 86 ++----------------
crates/gpui/src/app/window.rs                   |  6 
crates/gpui/src/elements.rs                     | 31 +----
crates/gpui/src/elements/align.rs               |  4 
crates/gpui/src/elements/canvas.rs              |  8 
crates/gpui/src/elements/clipped.rs             |  4 
crates/gpui/src/elements/component.rs           |  4 
crates/gpui/src/elements/constrained_box.rs     |  4 
crates/gpui/src/elements/container.rs           |  4 
crates/gpui/src/elements/empty.rs               |  4 
crates/gpui/src/elements/expanded.rs            |  4 
crates/gpui/src/elements/flex.rs                |  7 
crates/gpui/src/elements/hook.rs                |  4 
crates/gpui/src/elements/image.rs               |  4 
crates/gpui/src/elements/keystroke_label.rs     |  2 
crates/gpui/src/elements/label.rs               |  4 
crates/gpui/src/elements/list.rs                |  8 
crates/gpui/src/elements/mouse_event_handler.rs |  6 
crates/gpui/src/elements/overlay.rs             |  4 
crates/gpui/src/elements/resizable.rs           |  7 
crates/gpui/src/elements/stack.rs               |  4 
crates/gpui/src/elements/svg.rs                 |  3 
crates/gpui/src/elements/text.rs                |  4 
crates/gpui/src/elements/tooltip.rs             |  4 
crates/gpui/src/elements/uniform_list.rs        |  4 
crates/gpui2/src/adapter.rs                     | 12 +-
crates/gpui2/src/element.rs                     |  9 -
crates/gpui2/src/elements/div.rs                |  7 
crates/gpui2/src/elements/hoverable.rs          |  3 
crates/gpui2/src/elements/img.rs                |  2 
crates/gpui2/src/elements/pressable.rs          |  3 
crates/gpui2/src/elements/svg.rs                |  2 
crates/gpui2/src/elements/text.rs               |  3 
crates/gpui2/src/gpui2.rs                       |  1 
crates/gpui2/src/interactive.rs                 |  4 
crates/gpui2/src/paint_context.rs               | 50 -----------
crates/gpui2/src/style.rs                       |  6 
crates/gpui2/src/view_context.rs                | 34 +++++++
crates/gpui2_macros/src/derive_element.rs       |  2 
crates/gpui_macros/src/gpui_macros.rs           |  2 
crates/storybook/src/theme.rs                   |  7 
crates/terminal_view/src/terminal_element.rs    |  6 
crates/workspace/src/pane.rs                    |  6 
crates/workspace/src/pane_group.rs              |  4 
crates/workspace/src/status_bar.rs              |  6 
49 files changed, 156 insertions(+), 269 deletions(-)

Detailed changes

crates/collab_ui/src/collab_titlebar_item.rs 🔗

@@ -13,8 +13,8 @@ use gpui::{
     geometry::{rect::RectF, vector::vec2f, PathBuilder},
     json::{self, ToJson},
     platform::{CursorStyle, MouseButton},
-    AppContext, Entity, ImageData, ModelHandle, PaintContext, Subscription, View, ViewContext,
-    ViewHandle, WeakViewHandle,
+    AppContext, Entity, ImageData, ModelHandle, Subscription, View, ViewContext, ViewHandle,
+    WeakViewHandle,
 };
 use picker::PickerEvent;
 use project::{Project, RepositoryEntry};
@@ -1176,7 +1176,7 @@ impl Element<CollabTitlebarItem> for AvatarRibbon {
         _: RectF,
         _: &mut Self::LayoutState,
         _: &mut CollabTitlebarItem,
-        cx: &mut PaintContext<CollabTitlebarItem>,
+        cx: &mut ViewContext<CollabTitlebarItem>,
     ) -> Self::PaintState {
         let mut path = PathBuilder::new();
         path.reset(bounds.lower_left());

crates/collab_ui/src/face_pile.rs 🔗

@@ -7,7 +7,7 @@ use gpui::{
     },
     json::ToJson,
     serde_json::{self, json},
-    AnyElement, Axis, Element, PaintContext, View, ViewContext,
+    AnyElement, Axis, Element, View, ViewContext,
 };
 
 pub(crate) struct FacePile<V: View> {
@@ -57,7 +57,7 @@ impl<V: View> Element<V> for FacePile<V> {
         visible_bounds: RectF,
         _layout: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
 

crates/editor/src/element.rs 🔗

@@ -32,8 +32,8 @@ use gpui::{
     json::{self, ToJson},
     platform::{CursorStyle, Modifiers, MouseButton, MouseButtonEvent, MouseMovedEvent},
     text_layout::{self, Line, RunStyle, TextLayoutCache},
-    AnyElement, Axis, CursorRegion, Element, EventContext, FontCache, MouseRegion, PaintContext,
-    Quad, SizeConstraint, ViewContext, WindowContext,
+    AnyElement, Axis, CursorRegion, Element, EventContext, FontCache, MouseRegion, Quad,
+    SizeConstraint, ViewContext, WindowContext,
 };
 use itertools::Itertools;
 use json::json;
@@ -635,7 +635,7 @@ impl EditorElement {
         visible_bounds: RectF,
         layout: &mut LayoutState,
         editor: &mut Editor,
-        cx: &mut PaintContext<Editor>,
+        cx: &mut ViewContext<Editor>,
     ) {
         let line_height = layout.position_map.line_height;
 
@@ -778,7 +778,7 @@ impl EditorElement {
         visible_bounds: RectF,
         layout: &mut LayoutState,
         editor: &mut Editor,
-        cx: &mut PaintContext<Editor>,
+        cx: &mut ViewContext<Editor>,
     ) {
         let style = &self.style;
         let scroll_position = layout.position_map.snapshot.scroll_position();
@@ -1351,7 +1351,7 @@ impl EditorElement {
         visible_bounds: RectF,
         layout: &mut LayoutState,
         editor: &mut Editor,
-        cx: &mut PaintContext<Editor>,
+        cx: &mut ViewContext<Editor>,
     ) {
         let scroll_position = layout.position_map.snapshot.scroll_position();
         let scroll_left = scroll_position.x() * layout.position_map.em_width;
@@ -2570,7 +2570,7 @@ impl Element<Editor> for EditorElement {
         visible_bounds: RectF,
         layout: &mut Self::LayoutState,
         editor: &mut Editor,
-        cx: &mut PaintContext<Editor>,
+        cx: &mut ViewContext<Editor>,
     ) -> Self::PaintState {
         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
         cx.scene().push_layer(Some(visible_bounds));
@@ -3340,13 +3340,7 @@ mod tests {
         // Don't panic.
         let bounds = RectF::new(Default::default(), size);
         editor.update(cx, |editor, cx| {
-            element.paint(
-                bounds,
-                bounds,
-                &mut state,
-                editor,
-                &mut PaintContext::new(cx),
-            );
+            element.paint(bounds, bounds, &mut state, editor, cx);
         });
     }
 

crates/gpui/examples/corner_radii.rs 🔗

@@ -53,7 +53,7 @@ impl<V: View> gpui::Element<V> for CornersElement {
         _: pathfinder_geometry::rect::RectF,
         _: &mut Self::LayoutState,
         _: &mut V,
-        cx: &mut gpui::PaintContext<V>,
+        cx: &mut gpui::ViewContext<V>,
     ) -> Self::PaintState {
         cx.scene().push_quad(Quad {
             bounds,

crates/gpui/src/app.rs 🔗

@@ -3404,6 +3404,16 @@ impl<'a, 'b, V: 'static> ViewContext<'a, 'b, V> {
             .or_default()
             .push(self_view_id);
     }
+
+    pub fn paint_layer<F, R>(&mut self, clip_bounds: Option<RectF>, f: F) -> R
+    where
+        F: FnOnce(&mut Self) -> R,
+    {
+        self.scene().push_layer(clip_bounds);
+        let result = f(self);
+        self.scene().pop_layer();
+        result
+    }
 }
 
 impl<V: View> ViewContext<'_, '_, V> {
@@ -3495,82 +3505,6 @@ impl<V> BorrowWindowContext for ViewContext<'_, '_, V> {
     }
 }
 
-pub struct PaintContext<'a, 'b, 'c, V> {
-    pub view_context: &'c mut ViewContext<'a, 'b, V>,
-}
-
-impl<'a, 'b, 'c, V> PaintContext<'a, 'b, 'c, V> {
-    pub fn new(view_context: &'c mut ViewContext<'a, 'b, V>) -> Self {
-        Self { view_context }
-    }
-
-    pub fn paint_layer<F, R>(&mut self, clip_bounds: Option<RectF>, f: F) -> R
-    where
-        F: FnOnce(&mut Self) -> R,
-    {
-        self.scene().push_layer(clip_bounds);
-        let result = f(self);
-        self.scene().pop_layer();
-        result
-    }
-}
-
-impl<'a, 'b, 'c, V> Deref for PaintContext<'a, 'b, 'c, V> {
-    type Target = ViewContext<'a, 'b, V>;
-
-    fn deref(&self) -> &Self::Target {
-        &self.view_context
-    }
-}
-
-impl<V> DerefMut for PaintContext<'_, '_, '_, V> {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.view_context
-    }
-}
-
-impl<V> BorrowAppContext for PaintContext<'_, '_, '_, V> {
-    fn read_with<T, F: FnOnce(&AppContext) -> T>(&self, f: F) -> T {
-        BorrowAppContext::read_with(&*self.view_context, f)
-    }
-
-    fn update<T, F: FnOnce(&mut AppContext) -> T>(&mut self, f: F) -> T {
-        BorrowAppContext::update(&mut *self.view_context, f)
-    }
-}
-
-impl<V> BorrowWindowContext for PaintContext<'_, '_, '_, V> {
-    type Result<T> = T;
-
-    fn read_window<T, F>(&self, window: AnyWindowHandle, f: F) -> Self::Result<T>
-    where
-        F: FnOnce(&WindowContext) -> T,
-    {
-        BorrowWindowContext::read_window(self.view_context, window, f)
-    }
-
-    fn read_window_optional<T, F>(&self, window: AnyWindowHandle, f: F) -> Option<T>
-    where
-        F: FnOnce(&WindowContext) -> Option<T>,
-    {
-        BorrowWindowContext::read_window_optional(self.view_context, window, f)
-    }
-
-    fn update_window<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Self::Result<T>
-    where
-        F: FnOnce(&mut WindowContext) -> T,
-    {
-        BorrowWindowContext::update_window(self.view_context, window, f)
-    }
-
-    fn update_window_optional<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Option<T>
-    where
-        F: FnOnce(&mut WindowContext) -> Option<T>,
-    {
-        BorrowWindowContext::update_window_optional(self.view_context, window, f)
-    }
-}
-
 pub struct EventContext<'a, 'b, 'c, V> {
     view_context: &'c mut ViewContext<'a, 'b, V>,
     pub(crate) handled: bool,

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

@@ -16,8 +16,8 @@ use crate::{
     text_layout::TextLayoutCache,
     util::post_inc,
     Action, AnyView, AnyViewHandle, AnyWindowHandle, AppContext, BorrowAppContext,
-    BorrowWindowContext, Effect, Element, Entity, Handle, MouseRegion, MouseRegionId, PaintContext,
-    SceneBuilder, Subscription, View, ViewContext, ViewHandle, WindowInvalidation,
+    BorrowWindowContext, Effect, Element, Entity, Handle, MouseRegion, MouseRegionId, SceneBuilder,
+    Subscription, View, ViewContext, ViewHandle, WindowInvalidation,
 };
 use anyhow::{anyhow, bail, Result};
 use collections::{HashMap, HashSet};
@@ -1703,7 +1703,7 @@ impl<V: 'static> Element<V> for ChildView {
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         _: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) {
         if let Some(mut rendered_view) = cx.window.rendered_views.remove(&self.view_id) {
             rendered_view

crates/gpui/src/elements.rs 🔗

@@ -34,7 +34,7 @@ use crate::{
         rect::RectF,
         vector::{vec2f, Vector2F},
     },
-    json, Action, Entity, PaintContext, SizeConstraint, TypeTag, View, ViewContext, WeakViewHandle,
+    json, Action, Entity, SizeConstraint, TypeTag, View, ViewContext, WeakViewHandle,
     WindowContext,
 };
 use anyhow::{anyhow, Result};
@@ -68,7 +68,7 @@ pub trait Element<V: 'static>: 'static {
         visible_bounds: RectF,
         layout: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState;
 
     fn rect_for_text_range(
@@ -267,7 +267,7 @@ trait AnyElementState<V> {
         origin: Vector2F,
         visible_bounds: RectF,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     );
 
     fn rect_for_text_range(
@@ -347,7 +347,7 @@ impl<V, E: Element<V>> AnyElementState<V> for ElementState<V, E> {
         origin: Vector2F,
         visible_bounds: RectF,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) {
         *self = match mem::take(self) {
             ElementState::PostLayout {
@@ -357,13 +357,7 @@ impl<V, E: Element<V>> AnyElementState<V> for ElementState<V, E> {
                 mut layout,
             } => {
                 let bounds = RectF::new(origin, size);
-                let paint = element.paint(
-                    bounds,
-                    visible_bounds,
-                    &mut layout,
-                    view,
-                    &mut PaintContext::new(cx),
-                );
+                let paint = element.paint(bounds, visible_bounds, &mut layout, view, cx);
                 ElementState::PostPaint {
                     element,
                     constraint,
@@ -381,13 +375,7 @@ impl<V, E: Element<V>> AnyElementState<V> for ElementState<V, E> {
                 ..
             } => {
                 let bounds = RectF::new(origin, bounds.size());
-                let paint = element.paint(
-                    bounds,
-                    visible_bounds,
-                    &mut layout,
-                    view,
-                    &mut PaintContext::new(cx),
-                );
+                let paint = element.paint(bounds, visible_bounds, &mut layout, view, cx);
                 ElementState::PostPaint {
                     element,
                     constraint,
@@ -520,7 +508,7 @@ impl<V> AnyElement<V> {
         origin: Vector2F,
         visible_bounds: RectF,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) {
         self.state.paint(origin, visible_bounds, view, cx);
     }
@@ -582,7 +570,7 @@ impl<V: 'static> Element<V> for AnyElement<V> {
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         self.paint(bounds.origin(), visible_bounds, view, cx);
     }
@@ -674,8 +662,7 @@ impl<V: View> AnyRootElement for RootElement<V> {
             .ok_or_else(|| anyhow!("paint called on a root element for a dropped view"))?;
 
         view.update(cx, |view, cx| {
-            let mut cx = PaintContext::new(cx);
-            self.element.paint(origin, visible_bounds, view, &mut cx);
+            self.element.paint(origin, visible_bounds, view, cx);
             Ok(())
         })
     }

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

@@ -1,6 +1,6 @@
 use crate::{
     geometry::{rect::RectF, vector::Vector2F},
-    json, AnyElement, Element, PaintContext, SizeConstraint, ViewContext,
+    json, AnyElement, Element, SizeConstraint, ViewContext,
 };
 use json::ToJson;
 
@@ -68,7 +68,7 @@ impl<V: 'static> Element<V> for Align<V> {
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         let my_center = bounds.size() / 2.;
         let my_target = my_center + my_center * self.alignment;

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

@@ -3,7 +3,7 @@ use std::marker::PhantomData;
 use super::Element;
 use crate::{
     json::{self, json},
-    PaintContext, ViewContext,
+    ViewContext,
 };
 use json::ToJson;
 use pathfinder_geometry::{
@@ -15,7 +15,7 @@ pub struct Canvas<V, F>(F, PhantomData<V>);
 
 impl<V, F> Canvas<V, F>
 where
-    F: FnMut(RectF, RectF, &mut V, &mut PaintContext<V>),
+    F: FnMut(RectF, RectF, &mut V, &mut ViewContext<V>),
 {
     pub fn new(f: F) -> Self {
         Self(f, PhantomData)
@@ -24,7 +24,7 @@ where
 
 impl<V: 'static, F> Element<V> for Canvas<V, F>
 where
-    F: 'static + FnMut(RectF, RectF, &mut V, &mut PaintContext<V>),
+    F: 'static + FnMut(RectF, RectF, &mut V, &mut ViewContext<V>),
 {
     type LayoutState = ();
     type PaintState = ();
@@ -54,7 +54,7 @@ where
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         self.0(bounds, visible_bounds, view, cx)
     }

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

@@ -3,7 +3,7 @@ use std::ops::Range;
 use pathfinder_geometry::{rect::RectF, vector::Vector2F};
 use serde_json::json;
 
-use crate::{json, AnyElement, Element, PaintContext, SizeConstraint, ViewContext};
+use crate::{json, AnyElement, Element, SizeConstraint, ViewContext};
 
 pub struct Clipped<V> {
     child: AnyElement<V>,
@@ -34,7 +34,7 @@ impl<V: 'static> Element<V> for Clipped<V> {
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         cx.scene().push_layer(Some(bounds));
         let state = self.child.paint(bounds.origin(), visible_bounds, view, cx);

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

@@ -2,7 +2,7 @@ use std::{any::Any, marker::PhantomData};
 
 use pathfinder_geometry::{rect::RectF, vector::Vector2F};
 
-use crate::{AnyElement, Element, PaintContext, SizeConstraint, ViewContext};
+use crate::{AnyElement, Element, SizeConstraint, ViewContext};
 
 use super::Empty;
 
@@ -302,7 +302,7 @@ impl<V: 'static, C: StatefulComponent<V> + 'static> Element<V> for ComponentAdap
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         self.element
             .as_mut()

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

@@ -5,7 +5,7 @@ use serde_json::json;
 
 use crate::{
     geometry::{rect::RectF, vector::Vector2F},
-    json, AnyElement, Element, PaintContext, SizeConstraint, ViewContext,
+    json, AnyElement, Element, SizeConstraint, ViewContext,
 };
 
 pub struct ConstrainedBox<V> {
@@ -154,7 +154,7 @@ impl<V: 'static> Element<V> for ConstrainedBox<V> {
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         cx.scene().push_layer(Some(visible_bounds));
         self.child.paint(bounds.origin(), visible_bounds, view, cx);

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

@@ -10,7 +10,7 @@ use crate::{
     json::ToJson,
     platform::CursorStyle,
     scene::{self, CornerRadii, CursorRegion, Quad},
-    AnyElement, Element, PaintContext, SizeConstraint, ViewContext,
+    AnyElement, Element, SizeConstraint, ViewContext,
 };
 use schemars::JsonSchema;
 use serde::Deserialize;
@@ -391,7 +391,7 @@ impl<V: 'static> Element<V> for Container<V> {
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         let quad_bounds = RectF::from_points(
             bounds.origin() + vec2f(self.style.margin.left, self.style.margin.top),

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

@@ -6,7 +6,7 @@ use crate::{
         vector::{vec2f, Vector2F},
     },
     json::{json, ToJson},
-    PaintContext, ViewContext,
+    ViewContext,
 };
 use crate::{Element, SizeConstraint};
 
@@ -56,7 +56,7 @@ impl<V: 'static> Element<V> for Empty {
         _: RectF,
         _: &mut Self::LayoutState,
         _: &mut V,
-        _: &mut PaintContext<V>,
+        _: &mut ViewContext<V>,
     ) -> Self::PaintState {
     }
 

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

@@ -2,7 +2,7 @@ use std::ops::Range;
 
 use crate::{
     geometry::{rect::RectF, vector::Vector2F},
-    json, AnyElement, Element, PaintContext, SizeConstraint, ViewContext,
+    json, AnyElement, Element, SizeConstraint, ViewContext,
 };
 use serde_json::json;
 
@@ -60,7 +60,7 @@ impl<V: 'static> Element<V> for Expanded<V> {
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         self.child.paint(bounds.origin(), visible_bounds, view, cx);
     }

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

@@ -2,8 +2,7 @@ use std::{any::Any, cell::Cell, f32::INFINITY, ops::Range, rc::Rc};
 
 use crate::{
     json::{self, ToJson, Value},
-    AnyElement, Axis, Element, ElementStateHandle, PaintContext, SizeConstraint, Vector2FExt,
-    ViewContext,
+    AnyElement, Axis, Element, ElementStateHandle, SizeConstraint, Vector2FExt, ViewContext,
 };
 use pathfinder_geometry::{
     rect::RectF,
@@ -264,7 +263,7 @@ impl<V: 'static> Element<V> for Flex<V> {
         visible_bounds: RectF,
         remaining_space: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
 
@@ -454,7 +453,7 @@ impl<V: 'static> Element<V> for FlexItem<V> {
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         self.child.paint(bounds.origin(), visible_bounds, view, cx)
     }

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

@@ -3,7 +3,7 @@ use std::ops::Range;
 use crate::{
     geometry::{rect::RectF, vector::Vector2F},
     json::json,
-    AnyElement, Element, PaintContext, SizeConstraint, ViewContext,
+    AnyElement, Element, SizeConstraint, ViewContext,
 };
 
 pub struct Hook<V> {
@@ -51,7 +51,7 @@ impl<V: 'static> Element<V> for Hook<V> {
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) {
         self.child.paint(bounds.origin(), visible_bounds, view, cx);
     }

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

@@ -5,7 +5,7 @@ use crate::{
         vector::{vec2f, Vector2F},
     },
     json::{json, ToJson},
-    scene, Element, ImageData, PaintContext, SizeConstraint, ViewContext,
+    scene, Element, ImageData, SizeConstraint, ViewContext,
 };
 use schemars::JsonSchema;
 use serde::Deserialize;
@@ -95,7 +95,7 @@ impl<V: 'static> Element<V> for Image {
         _: RectF,
         layout: &mut Self::LayoutState,
         _: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         if let Some(data) = layout {
             cx.scene().push_image(scene::Image {

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

@@ -65,7 +65,7 @@ impl<V: 'static> Element<V> for KeystrokeLabel {
         visible_bounds: RectF,
         element: &mut AnyElement<V>,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) {
         element.paint(bounds.origin(), visible_bounds, view, cx);
     }

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

@@ -8,7 +8,7 @@ use crate::{
     },
     json::{ToJson, Value},
     text_layout::{Line, RunStyle},
-    Element, PaintContext, SizeConstraint, ViewContext,
+    Element, SizeConstraint, ViewContext,
 };
 use schemars::JsonSchema;
 use serde::Deserialize;
@@ -162,7 +162,7 @@ impl<V: 'static> Element<V> for Label {
         visible_bounds: RectF,
         line: &mut Self::LayoutState,
         _: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
         line.paint(bounds.origin(), visible_bounds, bounds.size().y(), cx)

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

@@ -4,7 +4,7 @@ use crate::{
         vector::{vec2f, Vector2F},
     },
     json::json,
-    AnyElement, Element, MouseRegion, PaintContext, SizeConstraint, ViewContext,
+    AnyElement, Element, MouseRegion, SizeConstraint, ViewContext,
 };
 use std::{cell::RefCell, collections::VecDeque, fmt::Debug, ops::Range, rc::Rc};
 use sum_tree::{Bias, SumTree};
@@ -253,7 +253,7 @@ impl<V: 'static> Element<V> for List<V> {
         visible_bounds: RectF,
         scroll_top: &mut ListOffset,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) {
         let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default();
         cx.scene().push_layer(Some(visible_bounds));
@@ -643,7 +643,7 @@ impl<'a> sum_tree::SeekTarget<'a, ListItemSummary, ListItemSummary> for Height {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::{elements::Empty, geometry::vector::vec2f, Entity, PaintContext};
+    use crate::{elements::Empty, geometry::vector::vec2f, Entity};
     use rand::prelude::*;
     use std::env;
 
@@ -949,7 +949,7 @@ mod tests {
             (self.size, ())
         }
 
-        fn paint(&mut self, _: RectF, _: RectF, _: &mut (), _: &mut V, _: &mut PaintContext<V>) {
+        fn paint(&mut self, _: RectF, _: RectF, _: &mut (), _: &mut V, _: &mut ViewContext<V>) {
             unimplemented!()
         }
 

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

@@ -10,8 +10,8 @@ use crate::{
         CursorRegion, HandlerSet, MouseClick, MouseClickOut, MouseDown, MouseDownOut, MouseDrag,
         MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut,
     },
-    AnyElement, Element, EventContext, MouseRegion, MouseState, PaintContext, SizeConstraint,
-    TypeTag, ViewContext,
+    AnyElement, Element, EventContext, MouseRegion, MouseState, SizeConstraint, TypeTag,
+    ViewContext,
 };
 use serde_json::json;
 use std::ops::Range;
@@ -281,7 +281,7 @@ impl<V: 'static> Element<V> for MouseEventHandler<V> {
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         if self.above {
             self.child.paint(bounds.origin(), visible_bounds, view, cx);

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

@@ -3,7 +3,7 @@ use std::ops::Range;
 use crate::{
     geometry::{rect::RectF, vector::Vector2F},
     json::ToJson,
-    AnyElement, Axis, Element, MouseRegion, PaintContext, SizeConstraint, ViewContext,
+    AnyElement, Axis, Element, MouseRegion, SizeConstraint, ViewContext,
 };
 use serde_json::json;
 
@@ -141,7 +141,7 @@ impl<V: 'static> Element<V> for Overlay<V> {
         _: RectF,
         size: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) {
         let (anchor_position, mut bounds) = match self.position_mode {
             OverlayPositionMode::Window => {

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

@@ -7,8 +7,7 @@ use serde_json::json;
 use crate::{
     geometry::rect::RectF,
     platform::{CursorStyle, MouseButton},
-    AnyElement, AppContext, Axis, Element, MouseRegion, PaintContext, SizeConstraint, TypeTag,
-    View, ViewContext,
+    AnyElement, AppContext, Axis, Element, MouseRegion, SizeConstraint, TypeTag, View, ViewContext,
 };
 
 #[derive(Copy, Clone, Debug)]
@@ -116,7 +115,7 @@ impl<V: 'static> Element<V> for Resizable<V> {
         visible_bounds: pathfinder_geometry::rect::RectF,
         constraint: &mut SizeConstraint,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         cx.scene().push_stacking_context(None, None);
 
@@ -252,7 +251,7 @@ impl<V: View, P: 'static> Element<V> for BoundsProvider<V, P> {
         visible_bounds: pathfinder_geometry::rect::RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut crate::PaintContext<V>,
+        cx: &mut crate::ViewContext<V>,
     ) -> Self::PaintState {
         cx.update_default_global::<ProviderMap, _, _>(|map, _| {
             map.0.insert(TypeTag::new::<P>(), (bounds, visible_bounds));

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

@@ -3,7 +3,7 @@ use std::ops::Range;
 use crate::{
     geometry::{rect::RectF, vector::Vector2F},
     json::{self, json, ToJson},
-    AnyElement, Element, PaintContext, SizeConstraint, ViewContext,
+    AnyElement, Element, SizeConstraint, ViewContext,
 };
 
 /// Element which renders it's children in a stack on top of each other.
@@ -56,7 +56,7 @@ impl<V: 'static> Element<V> for Stack<V> {
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         for child in &mut self.children {
             cx.scene().push_layer(None);

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

@@ -1,6 +1,5 @@
 use super::constrain_size_preserving_aspect_ratio;
 use crate::json::ToJson;
-use crate::PaintContext;
 use crate::{
     color::Color,
     geometry::{
@@ -73,7 +72,7 @@ impl<V: 'static> Element<V> for Svg {
         _visible_bounds: RectF,
         svg: &mut Self::LayoutState,
         _: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) {
         if let Some(svg) = svg.clone() {
             cx.scene().push_icon(scene::Icon {

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

@@ -7,7 +7,7 @@ use crate::{
     },
     json::{ToJson, Value},
     text_layout::{Line, RunStyle, ShapedBoundary},
-    Element, FontCache, PaintContext, SizeConstraint, TextLayoutCache, ViewContext, WindowContext,
+    Element, FontCache, SizeConstraint, TextLayoutCache, ViewContext, WindowContext,
 };
 use log::warn;
 use serde_json::json;
@@ -169,7 +169,7 @@ impl<V: 'static> Element<V> for Text {
         visible_bounds: RectF,
         layout: &mut Self::LayoutState,
         _: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         let mut origin = bounds.origin();
         let empty = Vec::new();

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

@@ -6,7 +6,7 @@ use crate::{
     fonts::TextStyle,
     geometry::{rect::RectF, vector::Vector2F},
     json::json,
-    Action, Axis, ElementStateHandle, PaintContext, SizeConstraint, Task, TypeTag, ViewContext,
+    Action, Axis, ElementStateHandle, SizeConstraint, Task, TypeTag, ViewContext,
 };
 use schemars::JsonSchema;
 use serde::Deserialize;
@@ -207,7 +207,7 @@ impl<V: 'static> Element<V> for Tooltip<V> {
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) {
         self.child.paint(bounds.origin(), visible_bounds, view, cx);
         if let Some(tooltip) = self.tooltip.as_mut() {

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

@@ -6,7 +6,7 @@ use crate::{
     },
     json::{self, json},
     platform::ScrollWheelEvent,
-    AnyElement, MouseRegion, PaintContext, ViewContext,
+    AnyElement, MouseRegion, ViewContext,
 };
 use json::ToJson;
 use std::{cell::RefCell, cmp, ops::Range, rc::Rc};
@@ -276,7 +276,7 @@ impl<V: 'static> Element<V> for UniformList<V> {
         visible_bounds: RectF,
         layout: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default();
 

crates/gpui2/src/adapter.rs 🔗

@@ -1,4 +1,4 @@
-use crate::{paint_context::PaintContext, ViewContext};
+use crate::ViewContext;
 use gpui::{geometry::rect::RectF, LayoutEngine, LayoutId};
 use util::ResultExt;
 
@@ -40,13 +40,13 @@ impl<V: 'static> gpui::Element<V> for AdapterElement<V> {
         _visible_bounds: RectF,
         layout_data: &mut Option<(LayoutEngine, LayoutId)>,
         view: &mut V,
-        legacy_cx: &mut gpui::PaintContext<V>,
+        cx: &mut gpui::ViewContext<V>,
     ) -> Self::PaintState {
         let (layout_engine, layout_id) = layout_data.take().unwrap();
-        legacy_cx.push_layout_engine(layout_engine);
-        let mut cx = PaintContext::new(legacy_cx);
-        self.0.paint(view, bounds.origin(), &mut cx);
-        *layout_data = legacy_cx.pop_layout_engine().zip(Some(layout_id));
+        cx.push_layout_engine(layout_engine);
+        self.0
+            .paint(view, bounds.origin(), &mut ViewContext::new(cx));
+        *layout_data = cx.pop_layout_engine().zip(Some(layout_id));
         debug_assert!(layout_data.is_some());
     }
 

crates/gpui2/src/element.rs 🔗

@@ -1,4 +1,3 @@
-pub use crate::paint_context::PaintContext;
 pub use crate::ViewContext;
 use anyhow::Result;
 use gpui::geometry::vector::Vector2F;
@@ -22,7 +21,7 @@ pub trait Element<V: 'static>: 'static + IntoElement<V> {
         parent_origin: Vector2F,
         layout: &Layout,
         state: &mut Self::PaintState,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) where
         Self: Sized;
 
@@ -40,7 +39,7 @@ pub trait Element<V: 'static>: 'static + IntoElement<V> {
 /// Used to make ElementState<V, E> into a trait object, so we can wrap it in AnyElement<V>.
 trait AnyStatefulElement<V> {
     fn layout(&mut self, view: &mut V, cx: &mut ViewContext<V>) -> Result<LayoutId>;
-    fn paint(&mut self, view: &mut V, parent_origin: Vector2F, cx: &mut PaintContext<V>);
+    fn paint(&mut self, view: &mut V, parent_origin: Vector2F, cx: &mut ViewContext<V>);
 }
 
 /// A wrapper around an element that stores its layout state.
@@ -105,7 +104,7 @@ impl<V, E: Element<V>> AnyStatefulElement<V> for StatefulElement<V, E> {
         result
     }
 
-    fn paint(&mut self, view: &mut V, parent_origin: Vector2F, cx: &mut PaintContext<V>) {
+    fn paint(&mut self, view: &mut V, parent_origin: Vector2F, cx: &mut ViewContext<V>) {
         self.phase = match std::mem::take(&mut self.phase) {
             ElementPhase::PostLayout {
                 layout_id,
@@ -149,7 +148,7 @@ impl<V> AnyElement<V> {
         self.0.layout(view, cx)
     }
 
-    pub fn paint(&mut self, view: &mut V, parent_origin: Vector2F, cx: &mut PaintContext<V>) {
+    pub fn paint(&mut self, view: &mut V, parent_origin: Vector2F, cx: &mut ViewContext<V>) {
         self.0.paint(view, parent_origin, cx)
     }
 }

crates/gpui2/src/elements/div.rs 🔗

@@ -3,7 +3,6 @@ use std::{cell::Cell, rc::Rc};
 use crate::{
     element::{AnyElement, Element, IntoElement, Layout, ParentElement},
     hsla,
-    paint_context::PaintContext,
     style::{CornerRadii, Overflow, Style, StyleHelpers, Styleable},
     InteractionHandlers, Interactive, ViewContext,
 };
@@ -69,7 +68,7 @@ impl<V: 'static> Element<V> for Div<V> {
         parent_origin: Vector2F,
         layout: &Layout,
         child_layouts: &mut Vec<LayoutId>,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) where
         Self: Sized,
     {
@@ -167,7 +166,7 @@ impl<V: 'static> Div<V> {
         bounds: RectF,
         overflow: Point<Overflow>,
         child_layout_ids: &[LayoutId],
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) {
         if overflow.y == Overflow::Scroll || overflow.x == Overflow::Scroll {
             let mut scroll_max = Vector2F::zero();
@@ -214,7 +213,7 @@ impl<V: 'static> Div<V> {
         }
     }
 
-    fn paint_inspector(&self, parent_origin: Vector2F, layout: &Layout, cx: &mut PaintContext<V>) {
+    fn paint_inspector(&self, parent_origin: Vector2F, layout: &Layout, cx: &mut ViewContext<V>) {
         let style = self.styles.merged();
         let bounds = layout.bounds + parent_origin;
 

crates/gpui2/src/elements/hoverable.rs 🔗

@@ -1,7 +1,6 @@
 use crate::{
     element::{AnyElement, Element, IntoElement, Layout, ParentElement},
     interactive::{InteractionHandlers, Interactive},
-    paint_context::PaintContext,
     style::{Style, StyleHelpers, Styleable},
     ViewContext,
 };
@@ -59,7 +58,7 @@ impl<V: 'static, E: Element<V> + Styleable> Element<V> for Hoverable<E> {
         parent_origin: Vector2F,
         layout: &Layout,
         paint_state: &mut Self::PaintState,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) where
         Self: Sized,
     {

crates/gpui2/src/elements/img.rs 🔗

@@ -53,7 +53,7 @@ impl<V: 'static> Element<V> for Img {
         parent_origin: Vector2F,
         layout: &gpui::Layout,
         _: &mut Self::PaintState,
-        cx: &mut crate::paint_context::PaintContext<V>,
+        cx: &mut crate::ViewContext<V>,
     ) where
         Self: Sized,
     {

crates/gpui2/src/elements/pressable.rs 🔗

@@ -1,7 +1,6 @@
 use crate::{
     element::{AnyElement, Element, IntoElement, Layout, ParentElement},
     interactive::{InteractionHandlers, Interactive},
-    paint_context::PaintContext,
     style::{Style, StyleHelpers, Styleable},
     ViewContext,
 };
@@ -59,7 +58,7 @@ impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
         parent_origin: Vector2F,
         layout: &Layout,
         paint_state: &mut Self::PaintState,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) where
         Self: Sized,
     {

crates/gpui2/src/elements/svg.rs 🔗

@@ -49,7 +49,7 @@ impl<V: 'static> Element<V> for Svg {
         parent_origin: Vector2F,
         layout: &Layout,
         _: &mut Self::PaintState,
-        cx: &mut crate::paint_context::PaintContext<V>,
+        cx: &mut crate::ViewContext<V>,
     ) where
         Self: Sized,
     {

crates/gpui2/src/elements/text.rs 🔗

@@ -1,6 +1,5 @@
 use crate::{
     element::{Element, IntoElement, Layout},
-    paint_context::PaintContext,
     ViewContext,
 };
 use anyhow::Result;
@@ -71,7 +70,7 @@ impl<V: 'static> Element<V> for Text {
         parent_origin: Vector2F,
         layout: &Layout,
         paint_state: &mut Self::PaintState,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) {
         let bounds = layout.bounds + parent_origin;
 

crates/gpui2/src/gpui2.rs 🔗

@@ -3,7 +3,6 @@ pub mod color;
 pub mod element;
 pub mod elements;
 pub mod interactive;
-pub mod paint_context;
 pub mod style;
 pub mod view;
 pub mod view_context;

crates/gpui2/src/interactive.rs 🔗

@@ -6,7 +6,7 @@ use gpui::{
 use smallvec::SmallVec;
 use std::{cell::Cell, rc::Rc};
 
-use crate::element::PaintContext;
+use crate::ViewContext;
 
 pub trait Interactive<V: 'static> {
     fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V>;
@@ -121,7 +121,7 @@ pub struct InteractionHandlers<V: 'static> {
 }
 
 impl<V: 'static> InteractionHandlers<V> {
-    pub fn paint(&self, order: u32, bounds: RectF, cx: &mut PaintContext<V>) {
+    pub fn paint(&self, order: u32, bounds: RectF, cx: &mut ViewContext<V>) {
         for handler in self.mouse_down.iter().cloned() {
             cx.on_event(order, move |view, event: &MouseButtonEvent, cx| {
                 if event.is_down && bounds.contains_point(event.position) {

crates/gpui2/src/paint_context.rs 🔗

@@ -1,50 +0,0 @@
-use anyhow::{anyhow, Result};
-use derive_more::{Deref, DerefMut};
-pub use gpui::taffy::tree::NodeId;
-use gpui::{
-    scene::EventHandler, EventContext, Layout, LayoutId, PaintContext as LegacyPaintContext,
-};
-use std::{any::TypeId, rc::Rc};
-
-#[derive(Deref, DerefMut)]
-pub struct PaintContext<'a, 'b, 'c, 'd, V> {
-    #[deref]
-    #[deref_mut]
-    pub(crate) legacy_cx: &'d mut LegacyPaintContext<'a, 'b, 'c, V>,
-}
-
-impl<'a, 'b, 'c, 'd, V: 'static> PaintContext<'a, 'b, 'c, 'd, V> {
-    pub fn new(legacy_cx: &'d mut LegacyPaintContext<'a, 'b, 'c, V>) -> Self {
-        Self { legacy_cx }
-    }
-
-    pub fn on_event<E: 'static>(
-        &mut self,
-        order: u32,
-        handler: impl Fn(&mut V, &E, &mut EventContext<V>) + 'static,
-    ) {
-        let view = self.weak_handle();
-
-        self.scene().event_handlers.push(EventHandler {
-            order,
-            handler: Rc::new(move |event, window_cx| {
-                if let Some(view) = view.upgrade(window_cx) {
-                    view.update(window_cx, |view, view_cx| {
-                        let mut event_cx = EventContext::new(view_cx);
-                        handler(view, event.downcast_ref().unwrap(), &mut event_cx);
-                        event_cx.bubble
-                    })
-                } else {
-                    true
-                }
-            }),
-            event_type: TypeId::of::<E>(),
-        })
-    }
-
-    pub(crate) fn computed_layout(&mut self, layout_id: LayoutId) -> Result<Layout> {
-        self.layout_engine()
-            .ok_or_else(|| anyhow!("no layout engine present"))?
-            .computed_layout(layout_id)
-    }
-}

crates/gpui2/src/style.rs 🔗

@@ -2,7 +2,7 @@ use crate::{
     color::Hsla,
     elements::hoverable::{hoverable, Hoverable},
     elements::pressable::{pressable, Pressable},
-    paint_context::PaintContext,
+    ViewContext,
 };
 pub use fonts::Style as FontStyle;
 pub use fonts::Weight as FontWeight;
@@ -164,7 +164,7 @@ impl Style {
     }
 
     /// Paints the background of an element styled with this style.
-    pub fn paint_background<V: 'static>(&self, bounds: RectF, cx: &mut PaintContext<V>) {
+    pub fn paint_background<V: 'static>(&self, bounds: RectF, cx: &mut ViewContext<V>) {
         let rem_size = cx.rem_size();
         if let Some(color) = self.fill.as_ref().and_then(Fill::color) {
             cx.scene().push_quad(gpui::Quad {
@@ -177,7 +177,7 @@ impl Style {
     }
 
     /// Paints the foreground of an element styled with this style.
-    pub fn paint_foreground<V: 'static>(&self, bounds: RectF, cx: &mut PaintContext<V>) {
+    pub fn paint_foreground<V: 'static>(&self, bounds: RectF, cx: &mut ViewContext<V>) {
         let rem_size = cx.rem_size();
 
         if let Some(color) = self.border_color {

crates/gpui2/src/view_context.rs 🔗

@@ -1,7 +1,9 @@
+use std::{any::TypeId, rc::Rc};
+
 use crate::{element::LayoutId, style::Style};
 use anyhow::{anyhow, Result};
 use derive_more::{Deref, DerefMut};
-use gpui::{geometry::Size, MeasureParams};
+use gpui::{geometry::Size, scene::EventHandler, EventContext, Layout, MeasureParams};
 pub use gpui::{taffy::tree::NodeId, ViewContext as LegacyViewContext};
 
 #[derive(Deref, DerefMut)]
@@ -44,4 +46,34 @@ impl<'a, 'b, 'c, V: 'static> ViewContext<'a, 'b, 'c, V> {
 
         Ok(layout_id)
     }
+
+    pub fn on_event<E: 'static>(
+        &mut self,
+        order: u32,
+        handler: impl Fn(&mut V, &E, &mut EventContext<V>) + 'static,
+    ) {
+        let view = self.weak_handle();
+
+        self.scene().event_handlers.push(EventHandler {
+            order,
+            handler: Rc::new(move |event, window_cx| {
+                if let Some(view) = view.upgrade(window_cx) {
+                    view.update(window_cx, |view, view_cx| {
+                        let mut event_cx = EventContext::new(view_cx);
+                        handler(view, event.downcast_ref().unwrap(), &mut event_cx);
+                        event_cx.bubble
+                    })
+                } else {
+                    true
+                }
+            }),
+            event_type: TypeId::of::<E>(),
+        })
+    }
+
+    pub(crate) fn computed_layout(&mut self, layout_id: LayoutId) -> Result<Layout> {
+        self.layout_engine()
+            .ok_or_else(|| anyhow!("no layout engine present"))?
+            .computed_layout(layout_id)
+    }
 }

crates/gpui2_macros/src/derive_element.rs 🔗

@@ -80,7 +80,7 @@ pub fn derive_element(input: TokenStream) -> TokenStream {
                 parent_origin: gpui2::Vector2F,
                 _: &gpui2::element::Layout,
                 rendered_element: &mut Self::PaintState,
-                cx: &mut gpui2::element::PaintContext<V>,
+                cx: &mut gpui2::ViewContext<V>,
             ) {
                 rendered_element.paint(view, parent_origin, cx);
             }

crates/gpui_macros/src/gpui_macros.rs 🔗

@@ -342,7 +342,7 @@ pub fn element_derive(input: TokenStream) -> TokenStream {
                 visible_bounds: gpui::geometry::rect::RectF,
                 element: &mut gpui::elements::AnyElement<V>,
                 view: &mut V,
-                cx: &mut gpui::PaintContext<V>,
+                cx: &mut gpui::ViewContext<V>,
             ) {
                 element.paint(bounds.origin(), visible_bounds, view, cx);
             }

crates/storybook/src/theme.rs 🔗

@@ -1,7 +1,6 @@
 use gpui2::{
-    color::Hsla,
-    element::{Element, PaintContext},
-    serde_json, AppContext, IntoElement, Vector2F, ViewContext, WindowContext,
+    color::Hsla, element::Element, serde_json, AppContext, IntoElement, Vector2F, ViewContext,
+    WindowContext,
 };
 use serde::{de::Visitor, Deserialize, Deserializer};
 use std::{collections::HashMap, fmt, marker::PhantomData};
@@ -162,7 +161,7 @@ impl<V: 'static, E: Element<V>> Element<V> for Themed<V, E> {
         parent_origin: Vector2F,
         layout: &gpui2::Layout,
         state: &mut Self::PaintState,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) where
         Self: Sized,
     {

crates/terminal_view/src/terminal_element.rs 🔗

@@ -10,8 +10,8 @@ use gpui::{
     platform::{CursorStyle, MouseButton},
     serde_json::json,
     text_layout::{Line, RunStyle},
-    AnyElement, Element, EventContext, FontCache, ModelContext, MouseRegion, PaintContext, Quad,
-    SizeConstraint, TextLayoutCache, ViewContext, WeakModelHandle, WindowContext,
+    AnyElement, Element, EventContext, FontCache, ModelContext, MouseRegion, Quad, SizeConstraint,
+    TextLayoutCache, ViewContext, WeakModelHandle, WindowContext,
 };
 use itertools::Itertools;
 use language::CursorShape;
@@ -733,7 +733,7 @@ impl Element<TerminalView> for TerminalElement {
         visible_bounds: RectF,
         layout: &mut Self::LayoutState,
         view: &mut TerminalView,
-        cx: &mut PaintContext<TerminalView>,
+        cx: &mut ViewContext<TerminalView>,
     ) -> Self::PaintState {
         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
 

crates/workspace/src/pane.rs 🔗

@@ -25,8 +25,8 @@ use gpui::{
     keymap_matcher::KeymapContext,
     platform::{CursorStyle, MouseButton, NavigationDirection, PromptLevel},
     Action, AnyViewHandle, AnyWeakViewHandle, AppContext, AsyncAppContext, Entity, EventContext,
-    ModelHandle, MouseRegion, PaintContext, Quad, Task, View, ViewContext, ViewHandle,
-    WeakViewHandle, WindowContext,
+    ModelHandle, MouseRegion, Quad, Task, View, ViewContext, ViewHandle, WeakViewHandle,
+    WindowContext,
 };
 use project::{Project, ProjectEntryId, ProjectPath};
 use serde::Deserialize;
@@ -2011,7 +2011,7 @@ impl<V: 'static> Element<V> for PaneBackdrop<V> {
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
-        cx: &mut PaintContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         let background = theme::current(cx).editor.background;
 

crates/workspace/src/pane_group.rs 🔗

@@ -594,7 +594,7 @@ mod element {
         json::{self, ToJson},
         platform::{CursorStyle, MouseButton},
         scene::MouseDrag,
-        AnyElement, Axis, CursorRegion, Element, EventContext, MouseRegion, PaintContext, RectFExt,
+        AnyElement, Axis, CursorRegion, Element, EventContext, MouseRegion, RectFExt,
         SizeConstraint, Vector2FExt, ViewContext,
     };
 
@@ -855,7 +855,7 @@ mod element {
             visible_bounds: RectF,
             remaining_space: &mut Self::LayoutState,
             view: &mut Workspace,
-            cx: &mut PaintContext<Workspace>,
+            cx: &mut ViewContext<Workspace>,
         ) -> Self::PaintState {
             let can_resize = settings::get::<WorkspaceSettings>(cx).active_pane_magnification == 1.;
             let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();

crates/workspace/src/status_bar.rs 🔗

@@ -8,8 +8,8 @@ use gpui::{
         vector::{vec2f, Vector2F},
     },
     json::{json, ToJson},
-    AnyElement, AnyViewHandle, Entity, PaintContext, SizeConstraint, Subscription, View,
-    ViewContext, ViewHandle, WindowContext,
+    AnyElement, AnyViewHandle, Entity, SizeConstraint, Subscription, View, ViewContext, ViewHandle,
+    WindowContext,
 };
 
 pub trait StatusItemView: View {
@@ -230,7 +230,7 @@ impl Element<StatusBar> for StatusBarElement {
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut StatusBar,
-        cx: &mut PaintContext<StatusBar>,
+        cx: &mut ViewContext<StatusBar>,
     ) -> Self::PaintState {
         let origin_y = bounds.upper_right().y();
         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();