@@ -1241,70 +1241,77 @@ impl Prepared {
12411241 continue ;
12421242 }
12431243
1244+ let interact_id = id. with ( d) ;
1245+
12441246 // Margin on either side of the scroll bar:
12451247 let inner_margin = show_factor * scroll_style. bar_inner_margin ;
12461248 let outer_margin = show_factor * scroll_style. bar_outer_margin ;
12471249
1250+ // bottom of a horizontal scroll (d==0).
1251+ // right of a vertical scroll (d==1).
1252+ let mut max_cross = outer_rect. max [ 1 - d] - outer_margin;
1253+
1254+ if ui. clip_rect ( ) . max [ 1 - d] - outer_margin < max_cross {
1255+ // Move the scrollbar so it is visible. This is needed in some cases.
1256+ // For instance:
1257+ // * When we have a vertical-only scroll area in a top level panel,
1258+ // and that panel is not wide enough for the contents.
1259+ // * When one ScrollArea is nested inside another, and the outer
1260+ // is scrolled so that the scroll-bars of the inner ScrollArea (us)
1261+ // is outside the clip rectangle.
1262+ // Really this should use the tighter clip_rect that ignores clip_rect_margin, but we don't store that.
1263+ // clip_rect_margin is quite a hack. It would be nice to get rid of it.
1264+ max_cross = ui. clip_rect ( ) . max [ 1 - d] - outer_margin;
1265+ }
1266+
1267+ let full_width = scroll_style. bar_width ;
1268+
1269+ // The bounding rect of a fully visible bar.
1270+ // When we hover this area, we should show the full bar:
1271+ let max_bar_rect = if d == 0 {
1272+ outer_rect. with_min_y ( max_cross - full_width)
1273+ } else {
1274+ outer_rect. with_min_x ( max_cross - full_width)
1275+ } ;
1276+
1277+ let sense = if scroll_source. scroll_bar && ui. is_enabled ( ) {
1278+ Sense :: click_and_drag ( )
1279+ } else {
1280+ Sense :: hover ( )
1281+ } ;
1282+
1283+ // We always sense interaction with the full width, even if we antimate it growing/shrinking.
1284+ // This is to present a more consistent target for our hit test code,
1285+ // and to avoid producing jitter in "thin widget" heuristics there.
1286+ // Also: it make sense to detect any hover where the scroll bar _will_ be.
1287+ let response = ui. interact ( max_bar_rect, interact_id, sense) ;
1288+
12481289 // top/bottom of a horizontal scroll (d==0).
12491290 // left/rigth of a vertical scroll (d==1).
1250- let mut cross = if scroll_style. floating {
1251- // The bounding rect of a fully visible bar.
1252- // When we hover this area, we should show the full bar:
1253- let max_bar_rect = if d == 0 {
1254- outer_rect. with_min_y ( outer_rect. max . y - outer_margin - scroll_style. bar_width )
1255- } else {
1256- outer_rect. with_min_x ( outer_rect. max . x - outer_margin - scroll_style. bar_width )
1257- } ;
1258-
1259- let is_hovering_bar_area = is_hovering_outer_rect
1260- && ui. rect_contains_pointer ( max_bar_rect)
1261- && !is_dragging_background
1262- || state. scroll_bar_interaction [ d] ;
1291+ let cross = if scroll_style. floating {
1292+ let is_hovering_bar_area = response. hovered ( ) || state. scroll_bar_interaction [ d] ;
12631293
12641294 let is_hovering_bar_area_t = ui
12651295 . ctx ( )
12661296 . animate_bool_responsive ( id. with ( ( d, "bar_hover" ) ) , is_hovering_bar_area) ;
12671297
12681298 let width = show_factor
12691299 * lerp (
1270- scroll_style. floating_width ..=scroll_style . bar_width ,
1300+ scroll_style. floating_width ..=full_width ,
12711301 is_hovering_bar_area_t,
12721302 ) ;
12731303
1274- let max_cross = outer_rect. max [ 1 - d] - outer_margin;
12751304 let min_cross = max_cross - width;
12761305 Rangef :: new ( min_cross, max_cross)
12771306 } else {
12781307 let min_cross = inner_rect. max [ 1 - d] + inner_margin;
1279- let max_cross = outer_rect. max [ 1 - d] - outer_margin;
12801308 Rangef :: new ( min_cross, max_cross)
12811309 } ;
12821310
1283- if ui. clip_rect ( ) . max [ 1 - d] < cross. max + outer_margin {
1284- // Move the scrollbar so it is visible. This is needed in some cases.
1285- // For instance:
1286- // * When we have a vertical-only scroll area in a top level panel,
1287- // and that panel is not wide enough for the contents.
1288- // * When one ScrollArea is nested inside another, and the outer
1289- // is scrolled so that the scroll-bars of the inner ScrollArea (us)
1290- // is outside the clip rectangle.
1291- // Really this should use the tighter clip_rect that ignores clip_rect_margin, but we don't store that.
1292- // clip_rect_margin is quite a hack. It would be nice to get rid of it.
1293- let width = cross. max - cross. min ;
1294- cross. max = ui. clip_rect ( ) . max [ 1 - d] - outer_margin;
1295- cross. min = cross. max - width;
1296- }
1297-
12981311 let outer_scroll_bar_rect = if d == 0 {
1299- Rect :: from_min_max (
1300- pos2 ( scroll_bar_rect. left ( ) , cross. min ) ,
1301- pos2 ( scroll_bar_rect. right ( ) , cross. max ) ,
1302- )
1312+ Rect :: from_x_y_ranges ( scroll_bar_rect. x_range ( ) , cross)
13031313 } else {
1304- Rect :: from_min_max (
1305- pos2 ( cross. min , scroll_bar_rect. top ( ) ) ,
1306- pos2 ( cross. max , scroll_bar_rect. bottom ( ) ) ,
1307- )
1314+ Rect :: from_x_y_ranges ( cross, scroll_bar_rect. y_range ( ) )
13081315 } ;
13091316
13101317 let from_content = |content| {
@@ -1344,14 +1351,6 @@ impl Prepared {
13441351
13451352 let handle_rect = calculate_handle_rect ( d, & state. offset ) ;
13461353
1347- let interact_id = id. with ( d) ;
1348- let sense = if scroll_source. scroll_bar && ui. is_enabled ( ) {
1349- Sense :: click_and_drag ( )
1350- } else {
1351- Sense :: hover ( )
1352- } ;
1353- let response = ui. interact ( outer_scroll_bar_rect, interact_id, sense) ;
1354-
13551354 state. scroll_bar_interaction [ d] = response. hovered ( ) || response. dragged ( ) ;
13561355
13571356 if let Some ( pointer_pos) = response. interact_pointer_pos ( ) {
0 commit comments