@@ -22,6 +22,9 @@ pub struct State {
22
22
/// If set, quickly but smoothly scroll to this target offset.
23
23
offset_target : [ Option < ScrollingToTarget > ; 2 ] ,
24
24
25
+ /// The offset value when the `offset_target` is set.
26
+ offset_target_start : [ Option < f32 > ; 2 ] ,
27
+
25
28
/// Were the scroll bars visible last frame?
26
29
show_scroll : Vec2b ,
27
30
@@ -52,6 +55,7 @@ impl Default for State {
52
55
Self {
53
56
offset : Vec2 :: ZERO ,
54
57
offset_target : Default :: default ( ) ,
58
+ offset_target_start : Default :: default ( ) ,
55
59
show_scroll : Vec2b :: FALSE ,
56
60
content_is_too_large : Vec2b :: FALSE ,
57
61
scroll_bar_interaction : Vec2b :: FALSE ,
@@ -839,22 +843,25 @@ impl Prepared {
839
843
840
844
let content_size = content_ui. min_size ( ) ;
841
845
842
- let scroll_delta = content_ui
843
- . ctx ( )
844
- . pass_state_mut ( |state| std:: mem:: take ( & mut state. scroll_delta ) ) ;
845
-
846
846
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
-
851
847
// We always take both scroll targets regardless of which scroll axes are enabled. This
852
848
// is to avoid them leaking to other scroll areas.
853
849
let scroll_target = content_ui
854
850
. ctx ( )
855
851
. pass_state_mut ( |state| state. scroll_target [ d] . take ( ) ) ;
856
852
857
853
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
+
858
865
if let Some ( target) = scroll_target {
859
866
let pass_state:: ScrollTarget {
860
867
range,
@@ -897,10 +904,14 @@ impl Prepared {
897
904
898
905
if !animated {
899
906
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] {
901
908
// For instance: the user is continuously calling `ui.scroll_to_cursor`,
902
909
// 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
+ }
904
915
} else {
905
916
// The further we scroll, the more time we take.
906
917
let now = ui. input ( |i| i. time ) ;
@@ -910,6 +921,7 @@ impl Prepared {
910
921
animation_time_span : ( now, now + animation_duration as f64 ) ,
911
922
target_offset,
912
923
} ) ;
924
+ state. offset_target_start [ d] = Some ( state. offset [ d] ) ;
913
925
}
914
926
ui. ctx ( ) . request_repaint ( ) ;
915
927
}
@@ -1020,16 +1032,19 @@ impl Prepared {
1020
1032
// Margin on either side of the scroll bar:
1021
1033
let inner_margin = show_factor * scroll_style. bar_inner_margin ;
1022
1034
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] ;
1023
1036
1024
1037
// top/bottom of a horizontal scroll (d==0).
1025
1038
// 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
+
1027
1042
// The bounding rect of a fully visible bar.
1028
1043
// When we hover this area, we should show the full bar:
1029
1044
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 )
1031
1046
} 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 )
1033
1048
} ;
1034
1049
1035
1050
let is_hovering_bar_area = is_hovering_outer_rect
@@ -1046,39 +1061,23 @@ impl Prepared {
1046
1061
is_hovering_bar_area_t,
1047
1062
) ;
1048
1063
1049
- let max_cross = outer_rect. max [ 1 - d] - outer_margin;
1050
1064
let min_cross = max_cross - width;
1051
1065
Rangef :: new ( min_cross, max_cross)
1052
1066
} else {
1053
1067
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;
1055
1069
Rangef :: new ( min_cross, max_cross)
1056
1070
} ;
1057
1071
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
-
1073
1072
let outer_scroll_bar_rect = if d == 0 {
1074
1073
Rect :: from_min_max (
1075
1074
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 ) ,
1077
1076
)
1078
1077
} else {
1079
1078
Rect :: from_min_max (
1080
1079
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 ( ) ) ,
1082
1081
)
1083
1082
} ;
1084
1083
0 commit comments