Style resize handles

Nathan Sobo and Max Brunsfeld created

We want the draggable area to be larger than the visual appearance, so we added a padding facility to MouseEventHandler that enlarges the "hit area" by the specified padding.

Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>

Change summary

gpui/src/elements/container.rs           |  8 +++---
gpui/src/elements/mouse_event_handler.rs | 27 ++++++++++++++++++++-----
zed/assets/themes/_base.toml             |  3 +
zed/src/workspace/sidebar.rs             |  5 ++++
4 files changed, 32 insertions(+), 11 deletions(-)

Detailed changes

gpui/src/elements/container.rs 🔗

@@ -271,10 +271,10 @@ impl ToJson for Margin {
 
 #[derive(Clone, Debug, Default)]
 pub struct Padding {
-    top: f32,
-    left: f32,
-    bottom: f32,
-    right: f32,
+    pub top: f32,
+    pub left: f32,
+    pub bottom: f32,
+    pub right: f32,
 }
 
 impl<'de> Deserialize<'de> for Padding {

gpui/src/elements/mouse_event_handler.rs 🔗

@@ -1,12 +1,15 @@
-use std::ops::DerefMut;
-
+use super::Padding;
 use crate::{
-    geometry::{rect::RectF, vector::Vector2F},
+    geometry::{
+        rect::RectF,
+        vector::{vec2f, Vector2F},
+    },
     platform::CursorStyle,
     CursorStyleHandle, DebugContext, Element, ElementBox, ElementStateHandle, ElementStateId,
     Event, EventContext, LayoutContext, MutableAppContext, PaintContext, SizeConstraint,
 };
 use serde_json::json;
+use std::ops::DerefMut;
 
 pub struct MouseEventHandler {
     state: ElementStateHandle<MouseState>,
@@ -15,6 +18,7 @@ pub struct MouseEventHandler {
     mouse_down_handler: Option<Box<dyn FnMut(&mut EventContext)>>,
     click_handler: Option<Box<dyn FnMut(&mut EventContext)>>,
     drag_handler: Option<Box<dyn FnMut(Vector2F, &mut EventContext)>>,
+    padding: Padding,
 }
 
 #[derive(Default)]
@@ -42,6 +46,7 @@ impl MouseEventHandler {
             mouse_down_handler: None,
             click_handler: None,
             drag_handler: None,
+            padding: Default::default(),
         }
     }
 
@@ -64,6 +69,11 @@ impl MouseEventHandler {
         self.drag_handler = Some(Box::new(handler));
         self
     }
+
+    pub fn with_padding(mut self, padding: Padding) -> Self {
+        self.padding = padding;
+        self
+    }
 }
 
 impl Element for MouseEventHandler {
@@ -103,13 +113,18 @@ impl Element for MouseEventHandler {
 
         let handled_in_child = self.child.dispatch_event(event, cx);
 
+        let hit_bounds = RectF::from_points(
+            bounds.origin() - vec2f(self.padding.left, self.padding.top),
+            bounds.lower_right() + vec2f(self.padding.right, self.padding.bottom),
+        );
+
         self.state.update(cx, |state, cx| match event {
             Event::MouseMoved {
                 position,
                 left_mouse_down,
             } => {
                 if !left_mouse_down {
-                    let mouse_in = bounds.contains_point(*position);
+                    let mouse_in = hit_bounds.contains_point(*position);
                     if state.hovered != mouse_in {
                         state.hovered = mouse_in;
                         if let Some(cursor_style) = cursor_style {
@@ -129,7 +144,7 @@ impl Element for MouseEventHandler {
                 handled_in_child
             }
             Event::LeftMouseDown { position, .. } => {
-                if !handled_in_child && bounds.contains_point(*position) {
+                if !handled_in_child && hit_bounds.contains_point(*position) {
                     state.clicked = true;
                     state.prev_drag_position = Some(*position);
                     cx.notify();
@@ -150,7 +165,7 @@ impl Element for MouseEventHandler {
                     }
                     cx.notify();
                     if let Some(handler) = click_handler {
-                        if bounds.contains_point(*position) {
+                        if hit_bounds.contains_point(*position) {
                             handler(cx);
                         }
                     }

zed/assets/themes/_base.toml 🔗

@@ -23,7 +23,8 @@ text = "$text.0"
 padding = { left = 10, right = 10 }
 
 [workspace.sidebar.resize_handle]
-margin = { left = 6 }
+padding = { left = 1 }
+background = "$surface.1"
 
 [workspace.sidebar.icon]
 color = "$text.2.color"

zed/src/workspace/sidebar.rs 🔗

@@ -158,6 +158,11 @@ impl Sidebar {
                 .with_style(&self.theme(settings).resize_handle)
                 .boxed()
         })
+        .with_padding(Padding {
+            left: 4.,
+            right: 4.,
+            ..Default::default()
+        })
         .with_cursor_style(CursorStyle::ResizeLeftRight)
         .on_drag(move |delta, cx| {
             let prev_width = *width.borrow();