gpui: Fix tab jitter from oversized scrolling (#42434)

This commit is contained in:
Xiaobo Liu authored and GitHub committed 2025-12-12 22:27:09 +00:00
1 parent 60f1e7e636
commit 369ae38efc
1 file changed
+53 -2
+53 -2
View File
@@ -3193,7 +3193,11 @@ impl ScrollHandle {
match active_item.strategy {
ScrollStrategy::FirstVisible => {
if state.overflow.y == Overflow::Scroll {
if bounds.top() + scroll_offset.y < state.bounds.top() {
let child_height = bounds.size.height;
let viewport_height = state.bounds.size.height;
if child_height > viewport_height {
scroll_offset.y = state.bounds.top() - bounds.top();
} else if bounds.top() + scroll_offset.y < state.bounds.top() {
scroll_offset.y = state.bounds.top() - bounds.top();
} else if bounds.bottom() + scroll_offset.y > state.bounds.bottom() {
scroll_offset.y = state.bounds.bottom() - bounds.bottom();
@@ -3206,7 +3210,11 @@ impl ScrollHandle {
}
if state.overflow.x == Overflow::Scroll {
if bounds.left() + scroll_offset.x < state.bounds.left() {
let child_width = bounds.size.width;
let viewport_width = state.bounds.size.width;
if child_width > viewport_width {
scroll_offset.x = state.bounds.left() - bounds.left();
} else if bounds.left() + scroll_offset.x < state.bounds.left() {
scroll_offset.x = state.bounds.left() - bounds.left();
} else if bounds.right() + scroll_offset.x > state.bounds.right() {
scroll_offset.x = state.bounds.right() - bounds.right();
@@ -3268,3 +3276,46 @@ impl ScrollHandle {
self.0.borrow().child_bounds.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn scroll_handle_aligns_wide_children_to_left_edge() {
let handle = ScrollHandle::new();
{
let mut state = handle.0.borrow_mut();
state.bounds = Bounds::new(point(px(0.), px(0.)), size(px(80.), px(20.)));
state.child_bounds = vec![Bounds::new(point(px(25.), px(0.)), size(px(200.), px(20.)))];
state.overflow.x = Overflow::Scroll;
state.active_item = Some(ScrollActiveItem {
index: 0,
strategy: ScrollStrategy::default(),
});
}
handle.scroll_to_active_item();
assert_eq!(handle.offset().x, px(-25.));
}
#[test]
fn scroll_handle_aligns_tall_children_to_top_edge() {
let handle = ScrollHandle::new();
{
let mut state = handle.0.borrow_mut();
state.bounds = Bounds::new(point(px(0.), px(0.)), size(px(20.), px(80.)));
state.child_bounds = vec![Bounds::new(point(px(0.), px(25.)), size(px(20.), px(200.)))];
state.overflow.y = Overflow::Scroll;
state.active_item = Some(ScrollActiveItem {
index: 0,
strategy: ScrollStrategy::default(),
});
}
handle.scroll_to_active_item();
assert_eq!(handle.offset().y, px(-25.));
}
}