@@ -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 ,
@@ -836,22 +840,25 @@ impl Prepared {
836840
837841 let content_size = content_ui. min_size ( ) ;
838842
839- let scroll_delta = content_ui
840- . ctx ( )
841- . pass_state_mut ( |state| std:: mem:: take ( & mut state. scroll_delta ) ) ;
842-
843843 for d in 0 ..2 {
844- // PassState::scroll_delta is inverted from the way we apply the delta, so we need to negate it.
845- let mut delta = -scroll_delta. 0 [ d] ;
846- let mut animation = scroll_delta. 1 ;
847-
848844 // We always take both scroll targets regardless of which scroll axes are enabled. This
849845 // is to avoid them leaking to other scroll areas.
850846 let scroll_target = content_ui
851847 . ctx ( )
852848 . pass_state_mut ( |state| state. scroll_target [ d] . take ( ) ) ;
853849
854850 if scroll_enabled[ d] {
851+ let ( scroll_delta_0, scroll_delta_1) = content_ui. ctx ( ) . pass_state_mut ( |state| {
852+ (
853+ std:: mem:: take ( & mut state. scroll_delta . 0 [ d] ) ,
854+ std:: mem:: take ( & mut state. scroll_delta . 1 ) ,
855+ )
856+ } ) ;
857+
858+ // PassState::scroll_delta is inverted from the way we apply the delta, so we need to negate it.
859+ let mut delta = -scroll_delta_0;
860+ let mut animation = scroll_delta_1;
861+
855862 if let Some ( target) = scroll_target {
856863 let pass_state:: ScrollTarget {
857864 range,
@@ -894,10 +901,14 @@ impl Prepared {
894901
895902 if !animated {
896903 state. offset [ d] = target_offset;
897- } else if let Some ( animation ) = & mut state. offset_target [ d] {
904+ } else if let Some ( scroll_to_target ) = & mut state. offset_target [ d] {
898905 // For instance: the user is continuously calling `ui.scroll_to_cursor`,
899906 // so we don't want to reset the animation, but perhaps update the target:
900- animation. target_offset = target_offset;
907+ if let Some ( offset_target_start) = state. offset_target_start [ d] . take ( ) {
908+ let new_target_offset = offset_target_start + delta;
909+ scroll_to_target. target_offset +=
910+ scroll_to_target. target_offset - new_target_offset;
911+ }
901912 } else {
902913 // The further we scroll, the more time we take.
903914 let now = ui. input ( |i| i. time ) ;
@@ -907,6 +918,7 @@ impl Prepared {
907918 animation_time_span : ( now, now + animation_duration as f64 ) ,
908919 target_offset,
909920 } ) ;
921+ state. offset_target_start [ d] = Some ( state. offset [ d] ) ;
910922 }
911923 ui. ctx ( ) . request_repaint ( ) ;
912924 }
@@ -1017,16 +1029,19 @@ impl Prepared {
10171029 // Margin on either side of the scroll bar:
10181030 let inner_margin = show_factor * scroll_style. bar_inner_margin ;
10191031 let outer_margin = show_factor * scroll_style. bar_outer_margin ;
1032+ let clip_max = ui. clip_rect ( ) . max [ 1 - d] - ui. spacing ( ) . item_spacing [ 1 - d] ;
10201033
10211034 // top/bottom of a horizontal scroll (d==0).
10221035 // left/rigth of a vertical scroll (d==1).
1023- let mut cross = if scroll_style. floating {
1036+ let cross = if scroll_style. floating {
1037+ let max_cross = outer_rect. max [ 1 - d] . at_most ( clip_max) - outer_margin;
1038+
10241039 // The bounding rect of a fully visible bar.
10251040 // When we hover this area, we should show the full bar:
10261041 let max_bar_rect = if d == 0 {
1027- outer_rect. with_min_y ( outer_rect . max . y - outer_margin - scroll_style. bar_width )
1042+ outer_rect. with_min_y ( max_cross - scroll_style. bar_width )
10281043 } else {
1029- outer_rect. with_min_x ( outer_rect . max . x - outer_margin - scroll_style. bar_width )
1044+ outer_rect. with_min_x ( max_cross - scroll_style. bar_width )
10301045 } ;
10311046
10321047 let is_hovering_bar_area = is_hovering_outer_rect
@@ -1043,39 +1058,23 @@ impl Prepared {
10431058 is_hovering_bar_area_t,
10441059 ) ;
10451060
1046- let max_cross = outer_rect. max [ 1 - d] - outer_margin;
10471061 let min_cross = max_cross - width;
10481062 Rangef :: new ( min_cross, max_cross)
10491063 } else {
10501064 let min_cross = inner_rect. max [ 1 - d] + inner_margin;
1051- let max_cross = outer_rect. max [ 1 - d] - outer_margin;
1065+ let max_cross = outer_rect. max [ 1 - d] . at_most ( clip_max ) - outer_margin;
10521066 Rangef :: new ( min_cross, max_cross)
10531067 } ;
10541068
1055- if ui. clip_rect ( ) . max [ 1 - d] < cross. max + outer_margin {
1056- // Move the scrollbar so it is visible. This is needed in some cases.
1057- // For instance:
1058- // * When we have a vertical-only scroll area in a top level panel,
1059- // and that panel is not wide enough for the contents.
1060- // * When one ScrollArea is nested inside another, and the outer
1061- // is scrolled so that the scroll-bars of the inner ScrollArea (us)
1062- // is outside the clip rectangle.
1063- // Really this should use the tighter clip_rect that ignores clip_rect_margin, but we don't store that.
1064- // clip_rect_margin is quite a hack. It would be nice to get rid of it.
1065- let width = cross. max - cross. min ;
1066- cross. max = ui. clip_rect ( ) . max [ 1 - d] - outer_margin;
1067- cross. min = cross. max - width;
1068- }
1069-
10701069 let outer_scroll_bar_rect = if d == 0 {
10711070 Rect :: from_min_max (
10721071 pos2 ( scroll_bar_rect. left ( ) , cross. min ) ,
1073- pos2 ( scroll_bar_rect. right ( ) , cross. max ) ,
1072+ pos2 ( scroll_bar_rect. right ( ) , cross. max + outer_margin ) ,
10741073 )
10751074 } else {
10761075 Rect :: from_min_max (
10771076 pos2 ( cross. min , scroll_bar_rect. top ( ) ) ,
1078- pos2 ( cross. max , scroll_bar_rect. bottom ( ) ) ,
1077+ pos2 ( cross. max + outer_margin , scroll_bar_rect. bottom ( ) ) ,
10791078 )
10801079 } ;
10811080
0 commit comments