1
0
mirror of https://github.com/emilk/egui.git synced 2026-06-26 22:53:14 -04:00

Only paint scroll fade on enabled axes

`paint_fade_areas` previously checked overflow on both axes regardless
of which directions were scroll-enabled. A horizontal-only ScrollArea
with non-zero overflow.y (which can happen when the inner ui's content
height differs from `inner_rect.size().y` for any reason) would draw
permanent top/bottom fades — visible as a stripe through the content
that never goes away because there's no way to scroll it off.

Gate the top/bottom fades behind `direction_enabled.y` and the
left/right fades behind `direction_enabled.x`. The ScrollArea already
owns this state; pass it through `show_viewport_dyn`.
This commit is contained in:
lucasmerlin
2026-05-10 01:50:37 +02:00
parent 90b83c780e
commit fca54dec2c

View File

@@ -1006,6 +1006,7 @@ impl ScrollArea {
let margin = self
.content_margin
.unwrap_or_else(|| ui.spacing().scroll.content_margin);
let direction_enabled = self.direction_enabled;
let mut prepared = self.begin(ui);
let id = prepared.id;
@@ -1027,7 +1028,7 @@ impl ScrollArea {
inner_rect,
};
paint_fade_areas(ui, &output);
paint_fade_areas(ui, &output, direction_enabled);
output
}
@@ -1509,9 +1510,13 @@ impl Prepared {
}
}
/// Paint fade-out gradients at the top and/or bottom of a scroll area to
/// Paint fade-out gradients at the edges of a scroll area to
/// indicate that more content is available beyond the visible region.
fn paint_fade_areas<R>(ui: &Ui, scroll_output: &ScrollAreaOutput<R>) {
///
/// Only fades for axes where scrolling is enabled — otherwise stray overflow
/// in a non-scrollable axis would draw a permanent fade with nothing to scroll
/// away to.
fn paint_fade_areas<R>(ui: &Ui, scroll_output: &ScrollAreaOutput<R>, direction_enabled: Vec2b) {
let crate::style::ScrollFadeStyle {
strength,
size: fade_size,
@@ -1531,65 +1536,69 @@ fn paint_fade_areas<R>(ui: &Ui, scroll_output: &ScrollAreaOutput<R>) {
.intersect(ui.min_rect())
.expand(ui.visuals().clip_rect_margin);
// Top fade: animate opacity based on how far we've scrolled down.
if 0.0 < offset.y {
let t = (offset.y / fade_size).clamp(0.0, 1.0) * strength;
let bg_faded = bg.gamma_multiply(t);
let rect = Rect::from_min_max(
paint_rect.left_top(),
pos2(paint_rect.right(), paint_rect.top() + fade_size),
);
ui.painter().add(Shape::gradient_rect(
rect,
Direction::TopDown,
[bg_faded, Color32::TRANSPARENT],
));
if direction_enabled.y {
// Top fade: animate opacity based on how far we've scrolled down.
if 0.0 < offset.y {
let t = (offset.y / fade_size).clamp(0.0, 1.0) * strength;
let bg_faded = bg.gamma_multiply(t);
let rect = Rect::from_min_max(
paint_rect.left_top(),
pos2(paint_rect.right(), paint_rect.top() + fade_size),
);
ui.painter().add(Shape::gradient_rect(
rect,
Direction::TopDown,
[bg_faded, Color32::TRANSPARENT],
));
}
// Bottom fade: animate opacity based on distance from the bottom.
let distance_from_bottom = overflow.y - offset.y;
if 0.0 < distance_from_bottom {
let t = (distance_from_bottom / fade_size).clamp(0.0, 1.0) * strength;
let bg_faded = bg.gamma_multiply(t);
let rect = Rect::from_min_max(
pos2(paint_rect.left(), paint_rect.bottom() - fade_size),
paint_rect.right_bottom(),
);
ui.painter().add(Shape::gradient_rect(
rect,
Direction::BottomUp,
[bg_faded, Color32::TRANSPARENT],
));
}
}
// Bottom fade: animate opacity based on distance from the bottom.
let distance_from_bottom = overflow.y - offset.y;
if 0.0 < distance_from_bottom {
let t = (distance_from_bottom / fade_size).clamp(0.0, 1.0) * strength;
let bg_faded = bg.gamma_multiply(t);
let rect = Rect::from_min_max(
pos2(paint_rect.left(), paint_rect.bottom() - fade_size),
paint_rect.right_bottom(),
);
ui.painter().add(Shape::gradient_rect(
rect,
Direction::BottomUp,
[bg_faded, Color32::TRANSPARENT],
));
}
if direction_enabled.x {
// Left fade: animate opacity based on how far we've scrolled right.
if 0.0 < offset.x {
let t = (offset.x / fade_size).clamp(0.0, 1.0) * strength;
let bg_faded = bg.gamma_multiply(t);
let rect = Rect::from_min_max(
paint_rect.left_top(),
pos2(paint_rect.left() + fade_size, paint_rect.bottom()),
);
ui.painter().add(Shape::gradient_rect(
rect,
Direction::LeftToRight,
[bg_faded, Color32::TRANSPARENT],
));
}
// Left fade: animate opacity based on how far we've scrolled right.
if 0.0 < offset.x {
let t = (offset.x / fade_size).clamp(0.0, 1.0) * strength;
let bg_faded = bg.gamma_multiply(t);
let rect = Rect::from_min_max(
paint_rect.left_top(),
pos2(paint_rect.left() + fade_size, paint_rect.bottom()),
);
ui.painter().add(Shape::gradient_rect(
rect,
Direction::LeftToRight,
[bg_faded, Color32::TRANSPARENT],
));
}
// Right fade: animate opacity based on distance from the right edge.
let distance_from_right = overflow.x - offset.x;
if 0.0 < distance_from_right {
let t = (distance_from_right / fade_size).clamp(0.0, 1.0) * strength;
let bg_faded = bg.gamma_multiply(t);
let rect = Rect::from_min_max(
pos2(paint_rect.right() - fade_size, paint_rect.top()),
paint_rect.right_bottom(),
);
ui.painter().add(Shape::gradient_rect(
rect,
Direction::RightToLeft,
[bg_faded, Color32::TRANSPARENT],
));
// Right fade: animate opacity based on distance from the right edge.
let distance_from_right = overflow.x - offset.x;
if 0.0 < distance_from_right {
let t = (distance_from_right / fade_size).clamp(0.0, 1.0) * strength;
let bg_faded = bg.gamma_multiply(t);
let rect = Rect::from_min_max(
pos2(paint_rect.right() - fade_size, paint_rect.top()),
paint_rect.right_bottom(),
);
ui.painter().add(Shape::gradient_rect(
rect,
Direction::RightToLeft,
[bg_faded, Color32::TRANSPARENT],
));
}
}
}