Introduce CursorRegion struct

Nathan Sobo and Antonio Scandurra created

This will blend in with an upcoming MouseRegion struct that sits next to it in the scene.

Co-Authored-By: Antonio Scandurra <me@as-cii.com>

Change summary

crates/editor/src/element.rs                    | 10 ++++--
crates/gpui/src/elements/container.rs           |  7 +++-
crates/gpui/src/elements/mouse_event_handler.rs |  9 ++++--
crates/gpui/src/gpui.rs                         |  2 
crates/gpui/src/presenter.rs                    | 13 ++++----
crates/gpui/src/scene.rs                        | 27 ++++++++++++------
6 files changed, 44 insertions(+), 24 deletions(-)

Detailed changes

crates/editor/src/element.rs 🔗

@@ -18,8 +18,9 @@ use gpui::{
     json::{self, ToJson},
     platform::CursorStyle,
     text_layout::{self, Line, RunStyle, TextLayoutCache},
-    AppContext, Axis, Border, Element, ElementBox, Event, EventContext, LayoutContext,
-    MutableAppContext, PaintContext, Quad, Scene, SizeConstraint, ViewContext, WeakViewHandle,
+    AppContext, Axis, Border, CursorRegion, Element, ElementBox, Event, EventContext,
+    LayoutContext, MutableAppContext, PaintContext, Quad, Scene, SizeConstraint, ViewContext,
+    WeakViewHandle,
 };
 use json::json;
 use language::{Bias, DiagnosticSeverity};
@@ -330,7 +331,10 @@ impl EditorElement {
         let content_origin = bounds.origin() + vec2f(layout.gutter_margin, 0.);
 
         cx.scene.push_layer(Some(bounds));
-        cx.scene.push_cursor_style(bounds, CursorStyle::IBeam);
+        cx.scene.push_cursor_region(CursorRegion {
+            bounds,
+            style: CursorStyle::IBeam,
+        });
 
         for (range, color) in &layout.highlighted_ranges {
             self.paint_highlighted_range(

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

@@ -7,7 +7,7 @@ use crate::{
     },
     json::ToJson,
     platform::CursorStyle,
-    scene::{self, Border, Quad},
+    scene::{self, Border, CursorRegion, Quad},
     Element, ElementBox, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
 };
 use serde::Deserialize;
@@ -213,7 +213,10 @@ impl Element for Container {
         }
 
         if let Some(style) = self.style.cursor {
-            cx.scene.push_cursor_style(quad_bounds, style);
+            cx.scene.push_cursor_region(CursorRegion {
+                bounds: quad_bounds,
+                style,
+            });
         }
 
         let child_origin =

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

@@ -5,6 +5,7 @@ use crate::{
         vector::{vec2f, Vector2F},
     },
     platform::CursorStyle,
+    scene::CursorRegion,
     DebugContext, Element, ElementBox, ElementStateContext, ElementStateHandle, Event,
     EventContext, LayoutContext, PaintContext, SizeConstraint,
 };
@@ -100,9 +101,11 @@ impl Element for MouseEventHandler {
         _: &mut Self::LayoutState,
         cx: &mut PaintContext,
     ) -> Self::PaintState {
-        if let Some(cursor_style) = self.cursor_style {
-            cx.scene
-                .push_cursor_style(self.hit_bounds(bounds), cursor_style);
+        if let Some(style) = self.cursor_style {
+            cx.scene.push_cursor_region(CursorRegion {
+                bounds: self.hit_bounds(bounds),
+                style,
+            });
         }
         self.child.paint(bounds.origin(), visible_bounds, cx);
     }

crates/gpui/src/gpui.rs 🔗

@@ -16,7 +16,7 @@ pub mod fonts;
 pub mod geometry;
 mod presenter;
 mod scene;
-pub use scene::{Border, Quad, Scene};
+pub use scene::{Border, CursorRegion, Quad, Scene};
 pub mod text_layout;
 pub use text_layout::TextLayoutCache;
 mod util;

crates/gpui/src/presenter.rs 🔗

@@ -5,6 +5,7 @@ use crate::{
     geometry::rect::RectF,
     json::{self, ToJson},
     platform::{CursorStyle, Event},
+    scene::CursorRegion,
     text_layout::TextLayoutCache,
     Action, AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AssetCache, ElementBox,
     ElementStateContext, Entity, FontSystem, ModelHandle, ReadModel, ReadView, Scene,
@@ -22,7 +23,7 @@ pub struct Presenter {
     window_id: usize,
     pub(crate) rendered_views: HashMap<usize, ElementBox>,
     parents: HashMap<usize, usize>,
-    cursor_styles: Vec<(RectF, CursorStyle)>,
+    cursor_regions: Vec<CursorRegion>,
     font_cache: Arc<FontCache>,
     text_layout_cache: TextLayoutCache,
     asset_cache: Arc<AssetCache>,
@@ -43,7 +44,7 @@ impl Presenter {
             window_id,
             rendered_views: cx.render_views(window_id, titlebar_height),
             parents: HashMap::new(),
-            cursor_styles: Default::default(),
+            cursor_regions: Default::default(),
             font_cache,
             text_layout_cache,
             asset_cache,
@@ -120,7 +121,7 @@ impl Presenter {
                 RectF::new(Vector2F::zero(), window_size),
             );
             self.text_layout_cache.finish_frame();
-            self.cursor_styles = scene.cursor_styles();
+            self.cursor_regions = scene.cursor_regions();
 
             if cx.window_is_active(self.window_id) {
                 if let Some(event) = self.last_mouse_moved_event.clone() {
@@ -184,9 +185,9 @@ impl Presenter {
 
                     if !left_mouse_down {
                         let mut style_to_assign = CursorStyle::Arrow;
-                        for (bounds, style) in self.cursor_styles.iter().rev() {
-                            if bounds.contains_point(position) {
-                                style_to_assign = *style;
+                        for region in self.cursor_regions.iter().rev() {
+                            if region.bounds.contains_point(position) {
+                                style_to_assign = region.style;
                                 break;
                             }
                         }

crates/gpui/src/scene.rs 🔗

@@ -33,7 +33,13 @@ pub struct Layer {
     image_glyphs: Vec<ImageGlyph>,
     icons: Vec<Icon>,
     paths: Vec<Path>,
-    cursor_styles: Vec<(RectF, CursorStyle)>,
+    cursor_regions: Vec<CursorRegion>,
+}
+
+#[derive(Copy, Clone)]
+pub struct CursorRegion {
+    pub bounds: RectF,
+    pub style: CursorStyle,
 }
 
 #[derive(Default, Debug)]
@@ -175,9 +181,9 @@ impl Scene {
         self.stacking_contexts.iter().flat_map(|s| &s.layers)
     }
 
-    pub fn cursor_styles(&self) -> Vec<(RectF, CursorStyle)> {
+    pub fn cursor_regions(&self) -> Vec<CursorRegion> {
         self.layers()
-            .flat_map(|layer| &layer.cursor_styles)
+            .flat_map(|layer| &layer.cursor_regions)
             .copied()
             .collect()
     }
@@ -206,8 +212,8 @@ impl Scene {
         self.active_layer().push_quad(quad)
     }
 
-    pub fn push_cursor_style(&mut self, bounds: RectF, style: CursorStyle) {
-        self.active_layer().push_cursor_style(bounds, style);
+    pub fn push_cursor_region(&mut self, region: CursorRegion) {
+        self.active_layer().push_cursor_region(region);
     }
 
     pub fn push_image(&mut self, image: Image) {
@@ -298,7 +304,7 @@ impl Layer {
             glyphs: Default::default(),
             icons: Default::default(),
             paths: Default::default(),
-            cursor_styles: Default::default(),
+            cursor_regions: Default::default(),
         }
     }
 
@@ -316,10 +322,13 @@ impl Layer {
         self.quads.as_slice()
     }
 
-    fn push_cursor_style(&mut self, bounds: RectF, style: CursorStyle) {
-        if let Some(bounds) = bounds.intersection(self.clip_bounds.unwrap_or(bounds)) {
+    fn push_cursor_region(&mut self, region: CursorRegion) {
+        if let Some(bounds) = region
+            .bounds
+            .intersection(self.clip_bounds.unwrap_or(region.bounds))
+        {
             if can_draw(bounds) {
-                self.cursor_styles.push((bounds, style));
+                self.cursor_regions.push(region);
             }
         }
     }