Detailed changes
@@ -5131,7 +5131,7 @@ impl EditorElement {
let is_singleton = self.editor.read(cx).is_singleton(cx);
let line_height = layout.position_map.line_height;
- window.set_cursor_style(CursorStyle::Arrow, Some(&layout.gutter_hitbox));
+ window.set_cursor_style(CursorStyle::Arrow, &layout.gutter_hitbox);
for LineNumberLayout {
shaped_line,
@@ -5158,9 +5158,9 @@ impl EditorElement {
// In singleton buffers, we select corresponding lines on the line number click, so use | -like cursor.
// In multi buffers, we open file at the line number clicked, so use a pointing hand cursor.
if is_singleton {
- window.set_cursor_style(CursorStyle::IBeam, Some(&hitbox));
+ window.set_cursor_style(CursorStyle::IBeam, &hitbox);
} else {
- window.set_cursor_style(CursorStyle::PointingHand, Some(&hitbox));
+ window.set_cursor_style(CursorStyle::PointingHand, &hitbox);
}
}
}
@@ -5378,7 +5378,7 @@ impl EditorElement {
.read(cx)
.all_diff_hunks_expanded()
{
- window.set_cursor_style(CursorStyle::PointingHand, Some(hunk_hitbox));
+ window.set_cursor_style(CursorStyle::PointingHand, hunk_hitbox);
}
}
}
@@ -5452,7 +5452,7 @@ impl EditorElement {
|window| {
let editor = self.editor.read(cx);
if editor.mouse_cursor_hidden {
- window.set_cursor_style(CursorStyle::None, None);
+ window.set_window_cursor_style(CursorStyle::None);
} else if editor
.hovered_link_state
.as_ref()
@@ -5460,13 +5460,10 @@ impl EditorElement {
{
window.set_cursor_style(
CursorStyle::PointingHand,
- Some(&layout.position_map.text_hitbox),
+ &layout.position_map.text_hitbox,
);
} else {
- window.set_cursor_style(
- CursorStyle::IBeam,
- Some(&layout.position_map.text_hitbox),
- );
+ window.set_cursor_style(CursorStyle::IBeam, &layout.position_map.text_hitbox);
};
self.paint_lines_background(layout, window, cx);
@@ -5607,6 +5604,7 @@ impl EditorElement {
let Some(scrollbars_layout) = layout.scrollbars_layout.take() else {
return;
};
+ let any_scrollbar_dragged = self.editor.read(cx).scroll_manager.any_scrollbar_dragged();
for (scrollbar_layout, axis) in scrollbars_layout.iter_scrollbars() {
let hitbox = &scrollbar_layout.hitbox;
@@ -5672,7 +5670,11 @@ impl EditorElement {
BorderStyle::Solid,
));
- window.set_cursor_style(CursorStyle::Arrow, Some(&hitbox));
+ if any_scrollbar_dragged {
+ window.set_window_cursor_style(CursorStyle::Arrow);
+ } else {
+ window.set_cursor_style(CursorStyle::Arrow, &hitbox);
+ }
}
})
}
@@ -5740,7 +5742,7 @@ impl EditorElement {
}
});
- if self.editor.read(cx).scroll_manager.any_scrollbar_dragged() {
+ if any_scrollbar_dragged {
window.on_mouse_event({
let editor = self.editor.clone();
move |_: &MouseUpEvent, phase, window, cx| {
@@ -6126,6 +6128,7 @@ impl EditorElement {
fn paint_minimap(&self, layout: &mut EditorLayout, window: &mut Window, cx: &mut App) {
if let Some(mut layout) = layout.minimap.take() {
let minimap_hitbox = layout.thumb_layout.hitbox.clone();
+ let dragging_minimap = self.editor.read(cx).scroll_manager.is_dragging_minimap();
window.paint_layer(layout.thumb_layout.hitbox.bounds, |window| {
window.with_element_namespace("minimap", |window| {
@@ -6177,7 +6180,11 @@ impl EditorElement {
});
});
- window.set_cursor_style(CursorStyle::Arrow, Some(&minimap_hitbox));
+ if dragging_minimap {
+ window.set_window_cursor_style(CursorStyle::Arrow);
+ } else {
+ window.set_cursor_style(CursorStyle::Arrow, &minimap_hitbox);
+ }
let minimap_axis = ScrollbarAxis::Vertical;
let pixels_per_line = (minimap_hitbox.size.height / layout.max_scroll_top)
@@ -6238,7 +6245,7 @@ impl EditorElement {
}
});
- if self.editor.read(cx).scroll_manager.is_dragging_minimap() {
+ if dragging_minimap {
window.on_mouse_event({
let editor = self.editor.clone();
move |event: &MouseUpEvent, phase, window, cx| {
@@ -61,7 +61,7 @@ impl Render for WindowShadow {
CursorStyle::ResizeUpRightDownLeft
}
},
- Some(&hitbox),
+ &hitbox,
);
},
)
@@ -1744,11 +1744,11 @@ impl Interactivity {
if let Some(drag) = cx.active_drag.as_ref() {
if let Some(mouse_cursor) = drag.cursor_style {
- window.set_cursor_style(mouse_cursor, None);
+ window.set_window_cursor_style(mouse_cursor);
}
} else {
if let Some(mouse_cursor) = style.mouse_cursor {
- window.set_cursor_style(mouse_cursor, Some(hitbox));
+ window.set_cursor_style(mouse_cursor, hitbox);
}
}
@@ -769,7 +769,7 @@ impl Element for InteractiveText {
.iter()
.any(|range| range.contains(&ix))
{
- window.set_cursor_style(crate::CursorStyle::PointingHand, Some(hitbox))
+ window.set_cursor_style(crate::CursorStyle::PointingHand, hitbox)
}
}
@@ -408,7 +408,7 @@ pub(crate) type AnyMouseListener =
#[derive(Clone)]
pub(crate) struct CursorStyleRequest {
- pub(crate) hitbox_id: Option<HitboxId>, // None represents whole window
+ pub(crate) hitbox_id: HitboxId,
pub(crate) style: CursorStyle,
}
@@ -622,6 +622,7 @@ pub(crate) struct Frame {
pub(crate) input_handlers: Vec<Option<PlatformInputHandler>>,
pub(crate) tooltip_requests: Vec<Option<TooltipRequest>>,
pub(crate) cursor_styles: Vec<CursorStyleRequest>,
+ window_cursor_style: Option<CursorStyle>,
#[cfg(any(test, feature = "test-support"))]
pub(crate) debug_bounds: FxHashMap<String, Bounds<Pixels>>,
#[cfg(any(feature = "inspector", debug_assertions))]
@@ -666,6 +667,7 @@ impl Frame {
input_handlers: Vec::new(),
tooltip_requests: Vec::new(),
cursor_styles: Vec::new(),
+ window_cursor_style: None,
#[cfg(any(test, feature = "test-support"))]
debug_bounds: FxHashMap::default(),
@@ -691,6 +693,7 @@ impl Frame {
self.window_control_hitboxes.clear();
self.deferred_draws.clear();
self.focus = None;
+ self.window_cursor_style = None;
#[cfg(any(feature = "inspector", debug_assertions))]
{
@@ -699,6 +702,17 @@ impl Frame {
}
}
+ pub(crate) fn cursor_style(&self, window: &Window) -> Option<CursorStyle> {
+ self.window_cursor_style.or_else(|| {
+ self.cursor_styles.iter().rev().find_map(|request| {
+ request
+ .hitbox_id
+ .is_hovered(window)
+ .then_some(request.style)
+ })
+ })
+ }
+
pub(crate) fn hit_test(&self, position: Point<Pixels>) -> HitTest {
let mut set_hover_hitbox_count = false;
let mut hit_test = HitTest::default();
@@ -2157,14 +2171,23 @@ impl Window {
/// Updates the cursor style at the platform level. This method should only be called
/// during the prepaint phase of element drawing.
- pub fn set_cursor_style(&mut self, style: CursorStyle, hitbox: Option<&Hitbox>) {
+ pub fn set_cursor_style(&mut self, style: CursorStyle, hitbox: &Hitbox) {
self.invalidator.debug_assert_paint();
self.next_frame.cursor_styles.push(CursorStyleRequest {
- hitbox_id: hitbox.map(|hitbox| hitbox.id),
+ hitbox_id: hitbox.id,
style,
});
}
+ /// Updates the cursor style for the entire window at the platform level. A cursor
+ /// style using this method will have precedence over any cursor style set using
+ /// `set_cursor_style`. This method should only be called during the prepaint
+ /// phase of element drawing.
+ pub fn set_window_cursor_style(&mut self, style: CursorStyle) {
+ self.invalidator.debug_assert_paint();
+ self.next_frame.window_cursor_style = Some(style);
+ }
+
/// Sets a tooltip to be rendered for the upcoming frame. This method should only be called
/// during the paint phase of element drawing.
pub fn set_tooltip(&mut self, tooltip: AnyTooltip) -> TooltipId {
@@ -3245,15 +3268,7 @@ impl Window {
if self.is_window_hovered() {
let style = self
.rendered_frame
- .cursor_styles
- .iter()
- .rev()
- .find(|request| {
- request
- .hitbox_id
- .map_or(true, |hitbox_id| hitbox_id.is_hovered(self))
- })
- .map(|request| request.style)
+ .cursor_style(self)
.unwrap_or(CursorStyle::Arrow);
cx.platform.set_cursor_style(style);
}
@@ -576,9 +576,9 @@ impl MarkdownElement {
.is_some();
if is_hovering_link {
- window.set_cursor_style(CursorStyle::PointingHand, Some(hitbox));
+ window.set_cursor_style(CursorStyle::PointingHand, hitbox);
} else {
- window.set_cursor_style(CursorStyle::IBeam, Some(hitbox));
+ window.set_cursor_style(CursorStyle::IBeam, hitbox);
}
let on_open_url = self.on_url_click.take();
@@ -974,9 +974,9 @@ impl Element for TerminalElement {
&& bounds.contains(&window.mouse_position())
&& self.terminal_view.read(cx).hover.is_some()
{
- window.set_cursor_style(gpui::CursorStyle::PointingHand, Some(&layout.hitbox));
+ window.set_cursor_style(gpui::CursorStyle::PointingHand, &layout.hitbox);
} else {
- window.set_cursor_style(gpui::CursorStyle::IBeam, Some(&layout.hitbox));
+ window.set_cursor_style(gpui::CursorStyle::IBeam, &layout.hitbox);
}
let original_cursor = layout.cursor.take();
@@ -330,7 +330,7 @@ mod uniform_list {
});
let mut hovered_hitbox_id = None;
for (i, hitbox) in hitboxes.iter().enumerate() {
- window.set_cursor_style(gpui::CursorStyle::PointingHand, Some(hitbox));
+ window.set_cursor_style(gpui::CursorStyle::PointingHand, hitbox);
let indent_guide = &self.indent_guides[i];
let fill_color = if hitbox.is_hovered(window) {
hovered_hitbox_id = Some(hitbox.id);
@@ -2,10 +2,10 @@ use std::{any::Any, cell::Cell, fmt::Debug, ops::Range, rc::Rc, sync::Arc};
use crate::{IntoElement, prelude::*, px, relative};
use gpui::{
- Along, App, Axis as ScrollbarAxis, BorderStyle, Bounds, ContentMask, Corners, Edges, Element,
- ElementId, Entity, EntityId, GlobalElementId, Hitbox, HitboxBehavior, Hsla, IsZero, LayoutId,
- ListState, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Point, ScrollHandle,
- ScrollWheelEvent, Size, Style, UniformListScrollHandle, Window, quad,
+ Along, App, Axis as ScrollbarAxis, BorderStyle, Bounds, ContentMask, Corners, CursorStyle,
+ Edges, Element, ElementId, Entity, EntityId, GlobalElementId, Hitbox, HitboxBehavior, Hsla,
+ IsZero, LayoutId, ListState, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Point,
+ ScrollHandle, ScrollWheelEvent, Size, Style, UniformListScrollHandle, Window, quad,
};
pub struct Scrollbar {
@@ -22,6 +22,12 @@ enum ThumbState {
Dragging(Pixels),
}
+impl ThumbState {
+ fn is_dragging(&self) -> bool {
+ matches!(*self, ThumbState::Dragging(_))
+ }
+}
+
impl ScrollableHandle for UniformListScrollHandle {
fn content_size(&self) -> Size<Pixels> {
self.0.borrow().base_handle.content_size()
@@ -236,7 +242,7 @@ impl Element for Scrollbar {
_inspector_id: Option<&gpui::InspectorElementId>,
bounds: Bounds<Pixels>,
_request_layout: &mut Self::RequestLayoutState,
- _prepaint: &mut Self::PrepaintState,
+ hitbox: &mut Self::PrepaintState,
window: &mut Window,
cx: &mut App,
) {
@@ -244,7 +250,8 @@ impl Element for Scrollbar {
window.with_content_mask(Some(ContentMask { bounds }), |window| {
let axis = self.kind;
let colors = cx.theme().colors();
- let thumb_base_color = match self.state.thumb_state.get() {
+ let thumb_state = self.state.thumb_state.get();
+ let thumb_base_color = match thumb_state {
ThumbState::Dragging(_) => colors.scrollbar_thumb_active_background,
ThumbState::Hover => colors.scrollbar_thumb_hover_background,
ThumbState::Inactive => colors.scrollbar_thumb_background,
@@ -285,6 +292,12 @@ impl Element for Scrollbar {
BorderStyle::default(),
));
+ if thumb_state.is_dragging() {
+ window.set_window_cursor_style(CursorStyle::Arrow);
+ } else {
+ window.set_cursor_style(CursorStyle::Arrow, hitbox);
+ }
+
let scroll = self.state.scroll_handle.clone();
enum ScrollbarMouseEvent {
@@ -1281,7 +1281,17 @@ mod element {
Axis::Vertical => CursorStyle::ResizeRow,
Axis::Horizontal => CursorStyle::ResizeColumn,
};
- window.set_cursor_style(cursor_style, Some(&handle.hitbox));
+
+ if layout
+ .dragged_handle
+ .borrow()
+ .is_some_and(|dragged_ix| dragged_ix == ix)
+ {
+ window.set_window_cursor_style(cursor_style);
+ } else {
+ window.set_cursor_style(cursor_style, &handle.hitbox);
+ }
+
window.paint_quad(gpui::fill(
handle.divider_bounds,
cx.theme().colors().pane_group_border,
@@ -7411,7 +7411,7 @@ pub fn client_side_decorations(
CursorStyle::ResizeUpRightDownLeft
}
},
- Some(&hitbox),
+ &hitbox,
);
},
)