Take into account multiple scroll deltas within a single frame (#3982)

Release Notes:

- Fixed an issue where all but the last scroll event would be dropped if
there were multiple within a single frame.
This commit is contained in:
Julia 2024-01-09 14:51:26 -05:00 committed by GitHub
commit 5b1894a9b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 74 additions and 51 deletions

View File

@ -28,7 +28,7 @@ use gpui::{
AnchorCorner, AnyElement, AvailableSpace, BorrowWindow, Bounds, ContentMask, Corners,
CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler, Hsla, InteractiveBounds,
InteractiveElement, IntoElement, ModifiersChangedEvent, MouseButton, MouseDownEvent,
MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, ScrollWheelEvent, ShapedLine,
MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, ScrollDelta, ScrollWheelEvent, ShapedLine,
SharedString, Size, StackingOrder, StatefulInteractiveElement, Style, Styled, TextRun,
TextStyle, View, ViewContext, WindowContext,
};
@ -581,41 +581,6 @@ impl EditorElement {
}
}
fn scroll(
editor: &mut Editor,
event: &ScrollWheelEvent,
position_map: &PositionMap,
bounds: &InteractiveBounds,
cx: &mut ViewContext<Editor>,
) {
if !bounds.visibly_contains(&event.position, cx) {
return;
}
let line_height = position_map.line_height;
let max_glyph_width = position_map.em_width;
let (delta, axis) = match event.delta {
gpui::ScrollDelta::Pixels(mut pixels) => {
//Trackpad
let axis = position_map.snapshot.ongoing_scroll.filter(&mut pixels);
(pixels, axis)
}
gpui::ScrollDelta::Lines(lines) => {
//Not trackpad
let pixels = point(lines.x * max_glyph_width, lines.y * line_height);
(pixels, None)
}
};
let scroll_position = position_map.snapshot.scroll_position();
let x = f32::from((scroll_position.x * max_glyph_width - delta.x) / max_glyph_width);
let y = f32::from((scroll_position.y * line_height - delta.y) / line_height);
let scroll_position = point(x, y).clamp(&point(0., 0.), &position_map.scroll_max);
editor.scroll(scroll_position, axis, cx);
cx.stop_propagation();
}
fn paint_background(
&self,
gutter_bounds: Bounds<Pixels>,
@ -2450,6 +2415,64 @@ impl EditorElement {
)
}
fn paint_scroll_wheel_listener(
&mut self,
interactive_bounds: &InteractiveBounds,
layout: &LayoutState,
cx: &mut WindowContext,
) {
cx.on_mouse_event({
let position_map = layout.position_map.clone();
let editor = self.editor.clone();
let interactive_bounds = interactive_bounds.clone();
let mut delta = ScrollDelta::default();
move |event: &ScrollWheelEvent, phase, cx| {
if phase == DispatchPhase::Bubble
&& interactive_bounds.visibly_contains(&event.position, cx)
{
delta = delta.coalesce(event.delta);
editor.update(cx, |editor, cx| {
let position = event.position;
let position_map: &PositionMap = &position_map;
let bounds = &interactive_bounds;
if !bounds.visibly_contains(&position, cx) {
return;
}
let line_height = position_map.line_height;
let max_glyph_width = position_map.em_width;
let (delta, axis) = match delta {
gpui::ScrollDelta::Pixels(mut pixels) => {
//Trackpad
let axis = position_map.snapshot.ongoing_scroll.filter(&mut pixels);
(pixels, axis)
}
gpui::ScrollDelta::Lines(lines) => {
//Not trackpad
let pixels =
point(lines.x * max_glyph_width, lines.y * line_height);
(pixels, None)
}
};
let scroll_position = position_map.snapshot.scroll_position();
let x = f32::from(
(scroll_position.x * max_glyph_width - delta.x) / max_glyph_width,
);
let y =
f32::from((scroll_position.y * line_height - delta.y) / line_height);
let scroll_position =
point(x, y).clamp(&point(0., 0.), &position_map.scroll_max);
editor.scroll(scroll_position, axis, cx);
cx.stop_propagation();
});
}
}
});
}
fn paint_mouse_listeners(
&mut self,
bounds: Bounds<Pixels>,
@ -2463,21 +2486,7 @@ impl EditorElement {
stacking_order: cx.stacking_order().clone(),
};
cx.on_mouse_event({
let position_map = layout.position_map.clone();
let editor = self.editor.clone();
let interactive_bounds = interactive_bounds.clone();
move |event: &ScrollWheelEvent, phase, cx| {
if phase == DispatchPhase::Bubble
&& interactive_bounds.visibly_contains(&event.position, cx)
{
editor.update(cx, |editor, cx| {
Self::scroll(editor, event, &position_map, &interactive_bounds, cx)
});
}
}
});
self.paint_scroll_wheel_listener(&interactive_bounds, layout, cx);
cx.on_mouse_event({
let position_map = layout.position_map.clone();

View File

@ -178,6 +178,20 @@ impl ScrollDelta {
ScrollDelta::Lines(delta) => point(line_height * delta.x, line_height * delta.y),
}
}
pub fn coalesce(self, other: ScrollDelta) -> ScrollDelta {
match (self, other) {
(ScrollDelta::Pixels(px_a), ScrollDelta::Pixels(px_b)) => {
ScrollDelta::Pixels(px_a + px_b)
}
(ScrollDelta::Lines(lines_a), ScrollDelta::Lines(lines_b)) => {
ScrollDelta::Lines(lines_a + lines_b)
}
_ => other,
}
}
}
#[derive(Clone, Debug, Default)]