Skip to content

Commit 5d22f0b

Browse files
authored
Update scroll_area.rs
1 parent f062083 commit 5d22f0b

File tree

1 file changed

+31
-32
lines changed

1 file changed

+31
-32
lines changed

crates/egui/src/containers/scroll_area.rs

+31-32
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ pub struct State {
2222
/// If set, quickly but smoothly scroll to this target offset.
2323
offset_target: [Option<ScrollingToTarget>; 2],
2424

25+
/// The offset value when the `offset_target` is set.
26+
offset_target_start: [Option<f32>; 2],
27+
2528
/// Were the scroll bars visible last frame?
2629
show_scroll: Vec2b,
2730

@@ -52,6 +55,7 @@ impl Default for State {
5255
Self {
5356
offset: Vec2::ZERO,
5457
offset_target: Default::default(),
58+
offset_target_start: Default::default(),
5559
show_scroll: Vec2b::FALSE,
5660
content_is_too_large: Vec2b::FALSE,
5761
scroll_bar_interaction: Vec2b::FALSE,
@@ -839,22 +843,25 @@ impl Prepared {
839843

840844
let content_size = content_ui.min_size();
841845

842-
let scroll_delta = content_ui
843-
.ctx()
844-
.pass_state_mut(|state| std::mem::take(&mut state.scroll_delta));
845-
846846
for d in 0..2 {
847-
// PassState::scroll_delta is inverted from the way we apply the delta, so we need to negate it.
848-
let mut delta = -scroll_delta.0[d];
849-
let mut animation = scroll_delta.1;
850-
851847
// We always take both scroll targets regardless of which scroll axes are enabled. This
852848
// is to avoid them leaking to other scroll areas.
853849
let scroll_target = content_ui
854850
.ctx()
855851
.pass_state_mut(|state| state.scroll_target[d].take());
856852

857853
if scroll_enabled[d] {
854+
let (scroll_delta_0, scroll_delta_1) = content_ui.ctx().pass_state_mut(|state| {
855+
(
856+
std::mem::take(&mut state.scroll_delta.0[d]),
857+
std::mem::take(&mut state.scroll_delta.1),
858+
)
859+
});
860+
861+
// PassState::scroll_delta is inverted from the way we apply the delta, so we need to negate it.
862+
let mut delta = -scroll_delta_0;
863+
let mut animation = scroll_delta_1;
864+
858865
if let Some(target) = scroll_target {
859866
let pass_state::ScrollTarget {
860867
range,
@@ -897,10 +904,14 @@ impl Prepared {
897904

898905
if !animated {
899906
state.offset[d] = target_offset;
900-
} else if let Some(animation) = &mut state.offset_target[d] {
907+
} else if let Some(scroll_to_target) = &mut state.offset_target[d] {
901908
// For instance: the user is continuously calling `ui.scroll_to_cursor`,
902909
// so we don't want to reset the animation, but perhaps update the target:
903-
animation.target_offset = target_offset;
910+
if let Some(offset_target_start) = state.offset_target_start[d].take() {
911+
let new_target_offset = offset_target_start + delta;
912+
scroll_to_target.target_offset +=
913+
scroll_to_target.target_offset - new_target_offset;
914+
}
904915
} else {
905916
// The further we scroll, the more time we take.
906917
let now = ui.input(|i| i.time);
@@ -910,6 +921,7 @@ impl Prepared {
910921
animation_time_span: (now, now + animation_duration as f64),
911922
target_offset,
912923
});
924+
state.offset_target_start[d] = Some(state.offset[d]);
913925
}
914926
ui.ctx().request_repaint();
915927
}
@@ -1020,16 +1032,19 @@ impl Prepared {
10201032
// Margin on either side of the scroll bar:
10211033
let inner_margin = show_factor * scroll_style.bar_inner_margin;
10221034
let outer_margin = show_factor * scroll_style.bar_outer_margin;
1035+
let clip_max = ui.clip_rect().max[1 - d] - ui.spacing().item_spacing[1 - d];
10231036

10241037
// top/bottom of a horizontal scroll (d==0).
10251038
// left/rigth of a vertical scroll (d==1).
1026-
let mut cross = if scroll_style.floating {
1039+
let cross = if scroll_style.floating {
1040+
let max_cross = outer_rect.max[1 - d].at_most(clip_max) - outer_margin;
1041+
10271042
// The bounding rect of a fully visible bar.
10281043
// When we hover this area, we should show the full bar:
10291044
let max_bar_rect = if d == 0 {
1030-
outer_rect.with_min_y(outer_rect.max.y - outer_margin - scroll_style.bar_width)
1045+
outer_rect.with_min_y(max_cross - scroll_style.bar_width)
10311046
} else {
1032-
outer_rect.with_min_x(outer_rect.max.x - outer_margin - scroll_style.bar_width)
1047+
outer_rect.with_min_x(max_cross - scroll_style.bar_width)
10331048
};
10341049

10351050
let is_hovering_bar_area = is_hovering_outer_rect
@@ -1046,39 +1061,23 @@ impl Prepared {
10461061
is_hovering_bar_area_t,
10471062
);
10481063

1049-
let max_cross = outer_rect.max[1 - d] - outer_margin;
10501064
let min_cross = max_cross - width;
10511065
Rangef::new(min_cross, max_cross)
10521066
} else {
10531067
let min_cross = inner_rect.max[1 - d] + inner_margin;
1054-
let max_cross = outer_rect.max[1 - d] - outer_margin;
1068+
let max_cross = outer_rect.max[1 - d].at_most(clip_max) - outer_margin;
10551069
Rangef::new(min_cross, max_cross)
10561070
};
10571071

1058-
if ui.clip_rect().max[1 - d] < cross.max + outer_margin {
1059-
// Move the scrollbar so it is visible. This is needed in some cases.
1060-
// For instance:
1061-
// * When we have a vertical-only scroll area in a top level panel,
1062-
// and that panel is not wide enough for the contents.
1063-
// * When one ScrollArea is nested inside another, and the outer
1064-
// is scrolled so that the scroll-bars of the inner ScrollArea (us)
1065-
// is outside the clip rectangle.
1066-
// Really this should use the tighter clip_rect that ignores clip_rect_margin, but we don't store that.
1067-
// clip_rect_margin is quite a hack. It would be nice to get rid of it.
1068-
let width = cross.max - cross.min;
1069-
cross.max = ui.clip_rect().max[1 - d] - outer_margin;
1070-
cross.min = cross.max - width;
1071-
}
1072-
10731072
let outer_scroll_bar_rect = if d == 0 {
10741073
Rect::from_min_max(
10751074
pos2(scroll_bar_rect.left(), cross.min),
1076-
pos2(scroll_bar_rect.right(), cross.max),
1075+
pos2(scroll_bar_rect.right(), cross.max + outer_margin),
10771076
)
10781077
} else {
10791078
Rect::from_min_max(
10801079
pos2(cross.min, scroll_bar_rect.top()),
1081-
pos2(cross.max, scroll_bar_rect.bottom()),
1080+
pos2(cross.max + outer_margin, scroll_bar_rect.bottom()),
10821081
)
10831082
};
10841083

0 commit comments

Comments
 (0)