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(), Screen::End => self.end(),
}; };
let content: Element<_> = column![screen, controls,] let content: Element<_> =
.max_width(540) column![screen, controls].max_width(540).spacing(20).into();
.spacing(20)
.padding(20)
.into();
let scrollable = scrollable(center_x(if self.debug { let scrollable = scrollable(center_x(if self.debug {
content.explain(Color::BLACK) content.explain(Color::BLACK)
} else { } else {
content content
})); }))
.spacing(10);
center_y(scrollable).into() center_y(scrollable).padding(10).into()
} }
fn can_continue(&self) -> bool { fn can_continue(&self) -> bool {

View file

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

View file

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