Fix scrollbar regression

This commit is contained in:
2026-03-22 01:20:11 -04:00
parent ed4c216f96
commit 0d73e43a92
2 changed files with 533 additions and 5 deletions

View File

@@ -313,9 +313,11 @@ fn layout_element(
perf_stats,
);
let provisional_content_height = content_size.height.max(viewport_rect.size.height);
let requested_offset_y = scroll_box.offset_y.max(0.0);
let provisional_max_offset_y =
(provisional_content_height - viewport_rect.size.height).max(0.0);
let mut offset_y = scroll_box.offset_y.max(0.0).min(provisional_max_offset_y);
let mut offset_y = requested_offset_y.min(provisional_max_offset_y);
let child_scene_start = scene.items.len();
if viewport_rect.size.width > 0.0 && viewport_rect.size.height > 0.0 {
scene.push_clip(viewport_rect, 0.0);
@@ -345,7 +347,31 @@ fn layout_element(
.max(actual_content_height.ceil())
.max(viewport_rect.size.height);
let max_offset_y = (content_height - viewport_rect.size.height).max(0.0);
offset_y = offset_y.min(max_offset_y);
let corrected_offset_y = requested_offset_y.min(max_offset_y);
if (corrected_offset_y - offset_y).abs() > f32::EPSILON
&& viewport_rect.size.width > 0.0
&& viewport_rect.size.height > 0.0
{
offset_y = corrected_offset_y;
scene.items.truncate(child_scene_start);
scene.push_clip(viewport_rect, 0.0);
interaction.children = layout_container_children(
element,
Rect::new(
viewport_rect.origin.x,
viewport_rect.origin.y - offset_y,
viewport_rect.size.width,
content_height,
),
&interaction.path,
scene,
text_system,
perf_stats,
);
scene.pop_clip();
} else {
offset_y = corrected_offset_y;
}
interaction.scroll_metrics = Some(ScrollMetrics {
viewport_rect,
content_height,
@@ -1701,6 +1727,41 @@ mod tests {
assert!(text_bottom >= viewport_bottom - 1.0);
}
#[test]
fn scroll_box_preserves_requested_offset_for_direct_text_children() {
let scrollbox_id = ElementId::new(23);
let root = Element::column().child(
Element::scroll_box(240.0)
.id(scrollbox_id)
.width(320.0)
.height(120.0)
.padding(Edges::all(8.0))
.child(Element::text(
"line 01\nline 02\nline 03\nline 04\nline 05\nline 06\nline 07\nline 08\nline 09\nline 10\nline 11\nline 12\nline 13\nline 14\nline 15\nline 16\nline 17\nline 18\nline 19\nline 20\nline 21\nline 22\nline 23\nline 24\nline 25\nline 26",
TextStyle::new(16.0, Color::rgb(0xFF, 0xFF, 0xFF)).with_line_height(20.0),
)),
);
let snapshot = layout_snapshot(1, UiSize::new(360.0, 220.0), &root);
let scroll_metrics = snapshot
.interaction_tree
.scroll_metrics_for_element(scrollbox_id)
.expect("scroll box should expose scroll metrics");
let visible_text = snapshot
.scene
.items
.iter()
.find_map(|item| match item {
DisplayItem::Text(text) => Some(text),
_ => None,
})
.expect("scroll box should emit direct text children");
assert!(scroll_metrics.max_offset_y > 240.0);
assert_eq!(scroll_metrics.offset_y, 240.0);
assert!(visible_text.origin.y < scroll_metrics.viewport_rect.origin.y);
}
#[test]
fn interaction_tree_hit_test_returns_deepest_pointer_target() {
let root = Element::column()