@@ -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