Allow AutoScroll styling in scrollable widget

This commit is contained in:
Héctor Ramón Jiménez 2025-11-28 08:56:32 +01:00
parent 99748b89de
commit c582687518
No known key found for this signature in database
GPG key ID: 7CC46565708259A7

View file

@ -1390,6 +1390,7 @@ where
origin, origin,
vertical: scrollbars.y.is_some(), vertical: scrollbars.y.is_some(),
horizontal: scrollbars.x.is_some(), horizontal: scrollbars.x.is_some(),
class: &self.class,
}))) })))
} else { } else {
None None
@ -1406,22 +1407,24 @@ where
} }
} }
struct AutoScrollIcon { struct AutoScrollIcon<'a, Class> {
origin: Point, origin: Point,
vertical: bool, vertical: bool,
horizontal: bool, horizontal: bool,
class: &'a Class,
} }
impl AutoScrollIcon { impl<Class> AutoScrollIcon<'_, Class> {
const SIZE: f32 = 40.0; const SIZE: f32 = 40.0;
const DOT: f32 = Self::SIZE / 10.0; const DOT: f32 = Self::SIZE / 10.0;
const PADDING: f32 = Self::SIZE / 10.0; const PADDING: f32 = Self::SIZE / 10.0;
} }
impl<Message, Theme, Renderer> core::Overlay<Message, Theme, Renderer> impl<Message, Theme, Renderer> core::Overlay<Message, Theme, Renderer>
for AutoScrollIcon for AutoScrollIcon<'_, Theme::Class<'_>>
where where
Renderer: text::Renderer, Renderer: text::Renderer,
Theme: Catalog,
{ {
fn layout(&mut self, _renderer: &Renderer, _bounds: Size) -> layout::Node { fn layout(&mut self, _renderer: &Renderer, _bounds: Size) -> layout::Node {
layout::Node::new(Size::new(Self::SIZE, Self::SIZE)) layout::Node::new(Size::new(Self::SIZE, Self::SIZE))
@ -1431,20 +1434,27 @@ where
fn draw( fn draw(
&self, &self,
renderer: &mut Renderer, renderer: &mut Renderer,
_theme: &Theme, theme: &Theme,
_style: &renderer::Style, _style: &renderer::Style,
layout: Layout<'_>, layout: Layout<'_>,
_cursor: mouse::Cursor, _cursor: mouse::Cursor,
) { ) {
let bounds = layout.bounds(); let bounds = layout.bounds();
let style = theme
.style(
self.class,
Status::Active {
is_horizontal_scrollbar_disabled: false,
is_vertical_scrollbar_disabled: false,
},
)
.auto_scroll;
renderer.with_layer(Rectangle::INFINITE, |renderer| { renderer.with_layer(Rectangle::INFINITE, |renderer| {
renderer.fill_quad( renderer.fill_quad(
renderer::Quad { renderer::Quad {
bounds, bounds,
border: border::rounded(bounds.width) border: style.border,
.color(Color::BLACK)
.width(1.0),
shadow: core::Shadow { shadow: core::Shadow {
color: Color::BLACK.scale_alpha(0.8), color: Color::BLACK.scale_alpha(0.8),
offset: Vector::new(1.0, 1.0), offset: Vector::new(1.0, 1.0),
@ -1452,7 +1462,7 @@ where
}, },
snap: false, snap: false,
}, },
Color::WHITE.scale_alpha(0.8), style.background,
); );
renderer.fill_quad( renderer.fill_quad(
@ -1466,7 +1476,7 @@ where
snap: false, snap: false,
..renderer::Quad::default() ..renderer::Quad::default()
}, },
Color::BLACK.scale_alpha(0.8), style.icon,
); );
let arrow = core::Text { let arrow = core::Text {
@ -1492,7 +1502,7 @@ where
bounds.center_x(), bounds.center_x(),
bounds.y + Self::PADDING - 1.0, bounds.y + Self::PADDING - 1.0,
), ),
Color::BLACK.scale_alpha(0.8), style.icon,
bounds, bounds,
); );
@ -1506,7 +1516,7 @@ where
bounds.center_x(), bounds.center_x(),
bounds.y + bounds.height - Self::PADDING + 1.0, bounds.y + bounds.height - Self::PADDING + 1.0,
), ),
Color::BLACK.scale_alpha(0.8), style.icon,
bounds, bounds,
); );
} }
@ -1522,7 +1532,7 @@ where
bounds.x + Self::PADDING, bounds.x + Self::PADDING,
bounds.center_y() + 1.0, bounds.center_y() + 1.0,
), ),
Color::BLACK.scale_alpha(0.8), style.icon,
bounds, bounds,
); );
@ -1536,7 +1546,7 @@ where
bounds.x + bounds.width - Self::PADDING, bounds.x + bounds.width - Self::PADDING,
bounds.center_y() + 1.0, bounds.center_y() + 1.0,
), ),
Color::BLACK.scale_alpha(0.8), style.icon,
bounds, bounds,
); );
} }
@ -2263,6 +2273,8 @@ pub struct Style {
pub horizontal_rail: Rail, pub horizontal_rail: Rail,
/// The [`Background`] of the gap between a horizontal and vertical scrollbar. /// The [`Background`] of the gap between a horizontal and vertical scrollbar.
pub gap: Option<Background>, pub gap: Option<Background>,
/// The appearance of the [`AutoScroll`] overlay.
pub auto_scroll: AutoScroll,
} }
/// The appearance of the scrollbar of a scrollable. /// The appearance of the scrollbar of a scrollable.
@ -2285,6 +2297,17 @@ pub struct Scroller {
pub border: Border, pub border: Border,
} }
/// The appearance of the autoscroll overlay of a scrollable.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct AutoScroll {
/// The [`Background`] of the [`AutoScroll`] overlay.
pub background: Background,
/// The [`Border`] of the [`AutoScroll`] overlay.
pub border: Border,
/// The [`Color`] for the arrow icons of the [`AutoScroll`] overlay.
pub icon: Color,
}
/// The theme catalog of a [`Scrollable`]. /// The theme catalog of a [`Scrollable`].
pub trait Catalog { pub trait Catalog {
/// The item class of the [`Catalog`]. /// The item class of the [`Catalog`].
@ -2325,12 +2348,21 @@ pub fn default(theme: &Theme, status: Status) -> Style {
}, },
}; };
let auto_scroll = AutoScroll {
background: palette.background.weak.color.scale_alpha(0.9).into(),
border: border::rounded(u32::MAX)
.width(1)
.color(palette.background.weak.text.scale_alpha(0.8)),
icon: palette.background.weak.text.scale_alpha(0.8),
};
match status { match status {
Status::Active { .. } => Style { Status::Active { .. } => Style {
container: container::Style::default(), container: container::Style::default(),
vertical_rail: scrollbar, vertical_rail: scrollbar,
horizontal_rail: scrollbar, horizontal_rail: scrollbar,
gap: None, gap: None,
auto_scroll,
}, },
Status::Hovered { Status::Hovered {
is_horizontal_scrollbar_hovered, is_horizontal_scrollbar_hovered,
@ -2358,6 +2390,7 @@ pub fn default(theme: &Theme, status: Status) -> Style {
scrollbar scrollbar
}, },
gap: None, gap: None,
auto_scroll,
} }
} }
Status::Dragged { Status::Dragged {
@ -2386,6 +2419,7 @@ pub fn default(theme: &Theme, status: Status) -> Style {
scrollbar scrollbar
}, },
gap: None, gap: None,
auto_scroll,
} }
} }
} }