gpui: Fix scroll area to support two-layer scrolling in different directions (#31062)

Release Notes:

- N/A

---

This change is used to solve the problem of not being able to respond
correctly in two-layer scrolling (in different directions). This is a
common practical requirement.

As in the example, in actual use, there may be a scene with a horizontal
scroll in a vertical scroll. Before the modification, if we scroll up
and down in the area that can scroll horizontally, it will not respond
(because it is blocked by the horizontal scroll layer).

## Before


https://github.com/user-attachments/assets/e8ea0118-52a5-44d8-b419-639d4b6c0793

## After


https://github.com/user-attachments/assets/aa14ddd7-5596-4dc5-9c6e-278aabdfef8e

----

This change may cause many side effects, causing some scrolling details
to be different from before, and more testing and analysis are needed.

I have tested some existing scenarios of Zed (such as opening the Branch
panel on the Editor and scrolling) and it seems to be correct (but it is
possible that I don’t know some interaction details). Here, the person
who added this line of code before needs to evaluate the original
purpose.
This commit is contained in:
Jason Lee 2025-06-07 01:06:09 +08:00 committed by GitHub
parent ac806d982b
commit d9efa2860f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 61 additions and 1 deletions

View file

@ -869,6 +869,7 @@ impl InfoPopover {
let keyboard_grace = Rc::clone(&self.keyboard_grace);
div()
.id("info_popover")
.occlude()
.elevation_2(cx)
// Prevent a mouse down/move on the popover from being propagated to the editor,
// because that would dismiss the popover.

View file

@ -0,0 +1,60 @@
use gpui::{
App, Application, Bounds, Context, Window, WindowBounds, WindowOptions, div, prelude::*, px,
size,
};
struct Scrollable {}
impl Render for Scrollable {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
div()
.size_full()
.id("vertical")
.p_4()
.overflow_scroll()
.bg(gpui::white())
.child("Example for test 2 way scroll in nested layout")
.child(
div()
.h(px(5000.))
.border_1()
.border_color(gpui::blue())
.bg(gpui::blue().opacity(0.05))
.p_4()
.child(
div()
.mb_5()
.w_full()
.id("horizontal")
.overflow_scroll()
.child(
div()
.w(px(2000.))
.h(px(150.))
.bg(gpui::green().opacity(0.1))
.hover(|this| this.bg(gpui::green().opacity(0.2)))
.border_1()
.border_color(gpui::green())
.p_4()
.child("Scroll Horizontal"),
),
)
.child("Scroll Vertical"),
)
}
}
fn main() {
Application::new().run(|cx: &mut App| {
let bounds = Bounds::centered(None, size(px(500.), px(500.0)), cx);
cx.open_window(
WindowOptions {
window_bounds: Some(WindowBounds::Windowed(bounds)),
..Default::default()
},
|_, cx| cx.new(|_| Scrollable {}),
)
.unwrap();
cx.activate(true);
});
}

View file

@ -2299,7 +2299,6 @@ impl Interactivity {
}
scroll_offset.y += delta_y;
scroll_offset.x += delta_x;
cx.stop_propagation();
if *scroll_offset != old_scroll_offset {
cx.notify(current_view);
}