Show embedded scrollbars only when necessary in scrollable

This commit is contained in:
Héctor Ramón Jiménez 2025-05-03 04:15:18 +02:00
parent 7a81e638a3
commit f78a87c409
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
3 changed files with 100 additions and 50 deletions

View file

@ -168,19 +168,17 @@ impl Tour {
Screen::End => self.end(),
};
let content: Element<_> = column![screen, controls,]
.max_width(540)
.spacing(20)
.padding(20)
.into();
let content: Element<_> =
column![screen, controls].max_width(540).spacing(20).into();
let scrollable = scrollable(center_x(if self.debug {
content.explain(Color::BLACK)
} else {
content
}));
}))
.spacing(10);
center_y(scrollable).into()
center_y(scrollable).padding(10).into()
}
fn can_continue(&self) -> bool {

View file

@ -104,6 +104,7 @@ impl WebSocket {
)
.id(MESSAGE_LOG.clone())
.height(Fill)
.spacing(10)
.into()
};

View file

@ -426,55 +426,104 @@ where
renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
let (right_padding, bottom_padding) = match self.direction {
let mut layout = |right_padding, bottom_padding| {
layout::padded(
limits,
self.width,
self.height,
Padding {
right: right_padding,
bottom: bottom_padding,
..Padding::ZERO
},
|limits| {
let child_limits = layout::Limits::new(
Size::new(limits.min().width, limits.min().height),
Size::new(
if self.direction.horizontal().is_some() {
f32::INFINITY
} else {
limits.max().width
},
if self.direction.vertical().is_some() {
f32::INFINITY
} else {
limits.max().height
},
),
);
self.content.as_widget().layout(
&mut tree.children[0],
renderer,
&child_limits,
)
},
)
};
match self.direction {
Direction::Vertical(Scrollbar {
width,
margin,
spacing: Some(spacing),
..
}) => (width + margin * 2.0 + spacing, 0.0),
Direction::Horizontal(Scrollbar {
})
| Direction::Horizontal(Scrollbar {
width,
margin,
spacing: Some(spacing),
..
}) => (0.0, width + margin * 2.0 + spacing),
_ => (0.0, 0.0),
};
}) => {
let is_vertical =
matches!(self.direction, Direction::Vertical(_));
layout::padded(
limits,
self.width,
self.height,
Padding {
right: right_padding,
bottom: bottom_padding,
..Padding::ZERO
},
|limits| {
let child_limits = layout::Limits::new(
Size::new(limits.min().width, limits.min().height),
Size::new(
if self.direction.horizontal().is_some() {
f32::INFINITY
} else {
limits.max().width
},
if self.direction.vertical().is_some() {
f32::INFINITY
} else {
limits.max().height
},
),
let padding = width + margin * 2.0 + spacing;
let state = tree.state.downcast_mut::<State>();
let status_quo = layout(
if is_vertical && state.is_scrollbar_visible {
padding
} else {
0.0
},
if !is_vertical && state.is_scrollbar_visible {
padding
} else {
0.0
},
);
self.content.as_widget().layout(
&mut tree.children[0],
renderer,
&child_limits,
)
},
)
let is_scrollbar_visible = if is_vertical {
status_quo.children()[0].size().height
> status_quo.size().height
} else {
status_quo.children()[0].size().width
> status_quo.size().width
};
if state.is_scrollbar_visible == is_scrollbar_visible {
status_quo
} else {
log::trace!("Scrollbar status quo has changed");
state.is_scrollbar_visible = is_scrollbar_visible;
layout(
if is_vertical && state.is_scrollbar_visible {
padding
} else {
0.0
},
if !is_vertical && state.is_scrollbar_visible {
padding
} else {
0.0
},
)
}
}
_ => layout(0.0, 0.0),
}
}
fn operate(
@ -1354,6 +1403,7 @@ struct State {
keyboard_modifiers: keyboard::Modifiers,
last_notified: Option<Viewport>,
last_scrolled: Option<Instant>,
is_scrollbar_visible: bool,
}
impl Default for State {
@ -1367,6 +1417,7 @@ impl Default for State {
keyboard_modifiers: keyboard::Modifiers::default(),
last_notified: None,
last_scrolled: None,
is_scrollbar_visible: false,
}
}
}
@ -1626,13 +1677,13 @@ impl Scrollbars {
) -> Self {
let translation = state.translation(direction, bounds, content_bounds);
let show_scrollbar_x = direction.horizontal().filter(|scrollbar| {
scrollbar.spacing.is_some() || content_bounds.width > bounds.width
});
let show_scrollbar_x = direction
.horizontal()
.filter(|_scrollbar| content_bounds.width > bounds.width);
let show_scrollbar_y = direction.vertical().filter(|scrollbar| {
scrollbar.spacing.is_some() || content_bounds.height > bounds.height
});
let show_scrollbar_y = direction
.vertical()
.filter(|_scrollbar| content_bounds.height > bounds.height);
let y_scrollbar = if let Some(vertical) = show_scrollbar_y {
let Scrollbar {