Increase type-safety of alignment in scrollable

This commit is contained in:
Héctor Ramón Jiménez 2023-07-12 09:49:14 +02:00
parent 44460f7b8b
commit 2b2f9c07d8
No known key found for this signature in database
GPG key ID: 140CC052C94F138E

View file

@ -295,7 +295,7 @@ where
cursor, cursor,
clipboard, clipboard,
shell, shell,
&self.direction, self.direction,
&self.on_scroll, &self.on_scroll,
|event, layout, cursor, clipboard, shell| { |event, layout, cursor, clipboard, shell| {
self.content.as_widget_mut().on_event( self.content.as_widget_mut().on_event(
@ -327,7 +327,7 @@ where
theme, theme,
layout, layout,
cursor, cursor,
&self.direction, self.direction,
&self.style, &self.style,
|renderer, layout, cursor, viewport| { |renderer, layout, cursor, viewport| {
self.content.as_widget().draw( self.content.as_widget().draw(
@ -355,7 +355,7 @@ where
tree.state.downcast_ref::<State>(), tree.state.downcast_ref::<State>(),
layout, layout,
cursor, cursor,
&self.direction, self.direction,
|layout, cursor, viewport| { |layout, cursor, viewport| {
self.content.as_widget().mouse_interaction( self.content.as_widget().mouse_interaction(
&tree.children[0], &tree.children[0],
@ -386,7 +386,7 @@ where
let content_layout = layout.children().next().unwrap(); let content_layout = layout.children().next().unwrap();
let content_bounds = content_layout.bounds(); let content_bounds = content_layout.bounds();
let offset = tree.state.downcast_ref::<State>().offset( let offset = tree.state.downcast_ref::<State>().offset(
&self.direction, self.direction,
bounds, bounds,
content_bounds, content_bounds,
); );
@ -494,7 +494,7 @@ pub fn update<Message>(
cursor: mouse::Cursor, cursor: mouse::Cursor,
clipboard: &mut dyn Clipboard, clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>, shell: &mut Shell<'_, Message>,
direction: &Direction, direction: Direction,
on_scroll: &Option<Box<dyn Fn(Viewport) -> Message + '_>>, on_scroll: &Option<Box<dyn Fn(Viewport) -> Message + '_>>,
update_content: impl FnOnce( update_content: impl FnOnce(
Event, Event,
@ -512,15 +512,6 @@ pub fn update<Message>(
let scrollbars = Scrollbars::new(state, direction, bounds, content_bounds); let scrollbars = Scrollbars::new(state, direction, bounds, content_bounds);
let horizontal_alignment = direction
.horizontal()
.map(|p| p.alignment)
.unwrap_or_default();
let vertical_alignment = direction
.vertical()
.map(|p| p.alignment)
.unwrap_or_default();
let (mouse_over_y_scrollbar, mouse_over_x_scrollbar) = let (mouse_over_y_scrollbar, mouse_over_x_scrollbar) =
scrollbars.is_mouse_over(cursor); scrollbars.is_mouse_over(cursor);
@ -571,11 +562,7 @@ pub fn update<Message>(
mouse::ScrollDelta::Pixels { x, y } => Vector::new(x, y), mouse::ScrollDelta::Pixels { x, y } => Vector::new(x, y),
}; };
state.scroll( state.scroll(delta, direction, bounds, content_bounds);
aligned_delta(delta, vertical_alignment, horizontal_alignment),
bounds,
content_bounds,
);
notify_on_scroll(state, on_scroll, bounds, content_bounds, shell); notify_on_scroll(state, on_scroll, bounds, content_bounds, shell);
@ -606,15 +593,7 @@ pub fn update<Message>(
cursor_position.y - scroll_box_touched_at.y, cursor_position.y - scroll_box_touched_at.y,
); );
state.scroll( state.scroll(delta, direction, bounds, content_bounds);
aligned_delta(
delta,
vertical_alignment,
horizontal_alignment,
),
bounds,
content_bounds,
);
state.scroll_area_touched_at = Some(cursor_position); state.scroll_area_touched_at = Some(cursor_position);
@ -658,7 +637,6 @@ pub fn update<Message>(
scrollbar.scroll_percentage_y( scrollbar.scroll_percentage_y(
scroller_grabbed_at, scroller_grabbed_at,
cursor_position, cursor_position,
vertical_alignment,
), ),
bounds, bounds,
content_bounds, content_bounds,
@ -692,7 +670,6 @@ pub fn update<Message>(
scrollbar.scroll_percentage_y( scrollbar.scroll_percentage_y(
scroller_grabbed_at, scroller_grabbed_at,
cursor_position, cursor_position,
vertical_alignment,
), ),
bounds, bounds,
content_bounds, content_bounds,
@ -735,7 +712,6 @@ pub fn update<Message>(
scrollbar.scroll_percentage_x( scrollbar.scroll_percentage_x(
scroller_grabbed_at, scroller_grabbed_at,
cursor_position, cursor_position,
horizontal_alignment,
), ),
bounds, bounds,
content_bounds, content_bounds,
@ -769,7 +745,6 @@ pub fn update<Message>(
scrollbar.scroll_percentage_x( scrollbar.scroll_percentage_x(
scroller_grabbed_at, scroller_grabbed_at,
cursor_position, cursor_position,
horizontal_alignment,
), ),
bounds, bounds,
content_bounds, content_bounds,
@ -800,7 +775,7 @@ pub fn mouse_interaction(
state: &State, state: &State,
layout: Layout<'_>, layout: Layout<'_>,
cursor: mouse::Cursor, cursor: mouse::Cursor,
direction: &Direction, direction: Direction,
content_interaction: impl FnOnce( content_interaction: impl FnOnce(
Layout<'_>, Layout<'_>,
mouse::Cursor, mouse::Cursor,
@ -853,7 +828,7 @@ pub fn draw<Renderer>(
theme: &Renderer::Theme, theme: &Renderer::Theme,
layout: Layout<'_>, layout: Layout<'_>,
cursor: mouse::Cursor, cursor: mouse::Cursor,
direction: &Direction, direction: Direction,
style: &<Renderer::Theme as StyleSheet>::Style, style: &<Renderer::Theme as StyleSheet>::Style,
draw_content: impl FnOnce(&mut Renderer, Layout<'_>, mouse::Cursor, &Rectangle), draw_content: impl FnOnce(&mut Renderer, Layout<'_>, mouse::Cursor, &Rectangle),
) where ) where
@ -1138,9 +1113,30 @@ impl State {
pub fn scroll( pub fn scroll(
&mut self, &mut self,
delta: Vector<f32>, delta: Vector<f32>,
direction: Direction,
bounds: Rectangle, bounds: Rectangle,
content_bounds: Rectangle, content_bounds: Rectangle,
) { ) {
let horizontal_alignment = direction
.horizontal()
.map(|p| p.alignment)
.unwrap_or_default();
let vertical_alignment = direction
.vertical()
.map(|p| p.alignment)
.unwrap_or_default();
let align = |alignment: Alignment, delta: f32| match alignment {
Alignment::Start => delta,
Alignment::End => -delta,
};
let delta = Vector::new(
align(horizontal_alignment, delta.x),
align(vertical_alignment, delta.y),
);
if bounds.height < content_bounds.height { if bounds.height < content_bounds.height {
self.offset_y = Offset::Absolute( self.offset_y = Offset::Absolute(
(self.offset_y.absolute(bounds.height, content_bounds.height) (self.offset_y.absolute(bounds.height, content_bounds.height)
@ -1213,7 +1209,7 @@ impl State {
/// the bounds of the [`Scrollable`] and its contents. /// the bounds of the [`Scrollable`] and its contents.
pub fn offset( pub fn offset(
&self, &self,
direction: &Direction, direction: Direction,
bounds: Rectangle, bounds: Rectangle,
content_bounds: Rectangle, content_bounds: Rectangle,
) -> Vector { ) -> Vector {
@ -1258,7 +1254,7 @@ impl Scrollbars {
/// Create y and/or x scrollbar(s) if content is overflowing the [`Scrollable`] bounds. /// Create y and/or x scrollbar(s) if content is overflowing the [`Scrollable`] bounds.
fn new( fn new(
state: &State, state: &State,
direction: &Direction, direction: Direction,
bounds: Rectangle, bounds: Rectangle,
content_bounds: Rectangle, content_bounds: Rectangle,
) -> Self { ) -> Self {
@ -1327,6 +1323,7 @@ impl Scrollbars {
scroller: internals::Scroller { scroller: internals::Scroller {
bounds: scroller_bounds, bounds: scroller_bounds,
}, },
alignment: vertical.alignment,
}) })
} else { } else {
None None
@ -1387,6 +1384,7 @@ impl Scrollbars {
scroller: internals::Scroller { scroller: internals::Scroller {
bounds: scroller_bounds, bounds: scroller_bounds,
}, },
alignment: horizontal.alignment,
}) })
} else { } else {
None None
@ -1450,39 +1448,17 @@ impl Scrollbars {
} }
} }
fn aligned_delta(
delta: Vector,
vertical_alignment: Alignment,
horizontal_alignment: Alignment,
) -> Vector {
let align = |alignment: Alignment, delta: f32| match alignment {
Alignment::Start => delta,
Alignment::End => -delta,
};
Vector::new(
align(horizontal_alignment, delta.x),
align(vertical_alignment, delta.y),
)
}
pub(super) mod internals { pub(super) mod internals {
use crate::core::{Point, Rectangle}; use crate::core::{Point, Rectangle};
use super::Alignment; use super::Alignment;
/// The scrollbar of a [`Scrollable`].
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Scrollbar { pub struct Scrollbar {
/// The total bounds of the [`Scrollbar`], including the scrollbar, the scroller,
/// and the scrollbar margin.
pub total_bounds: Rectangle, pub total_bounds: Rectangle,
/// The bounds of just the [`Scrollbar`].
pub bounds: Rectangle, pub bounds: Rectangle,
/// The state of this scrollbar's [`Scroller`].
pub scroller: Scroller, pub scroller: Scroller,
pub alignment: Alignment,
} }
impl Scrollbar { impl Scrollbar {
@ -1496,7 +1472,6 @@ pub(super) mod internals {
&self, &self,
grabbed_at: f32, grabbed_at: f32,
cursor_position: Point, cursor_position: Point,
alignment: Alignment,
) -> f32 { ) -> f32 {
let pct = if cursor_position.x < 0.0 && cursor_position.y < 0.0 { let pct = if cursor_position.x < 0.0 && cursor_position.y < 0.0 {
// cursor position is unavailable! Set to either end or beginning of scrollbar depending // cursor position is unavailable! Set to either end or beginning of scrollbar depending
@ -1509,7 +1484,7 @@ pub(super) mod internals {
/ (self.bounds.height - self.scroller.bounds.height) / (self.bounds.height - self.scroller.bounds.height)
}; };
match alignment { match self.alignment {
Alignment::Start => pct, Alignment::Start => pct,
Alignment::End => 1.0 - pct, Alignment::End => 1.0 - pct,
} }
@ -1520,7 +1495,6 @@ pub(super) mod internals {
&self, &self,
grabbed_at: f32, grabbed_at: f32,
cursor_position: Point, cursor_position: Point,
alignment: Alignment,
) -> f32 { ) -> f32 {
let pct = if cursor_position.x < 0.0 && cursor_position.y < 0.0 { let pct = if cursor_position.x < 0.0 && cursor_position.y < 0.0 {
(self.scroller.bounds.x / self.total_bounds.width).round() (self.scroller.bounds.x / self.total_bounds.width).round()
@ -1531,7 +1505,7 @@ pub(super) mod internals {
/ (self.bounds.width - self.scroller.bounds.width) / (self.bounds.width - self.scroller.bounds.width)
}; };
match alignment { match self.alignment {
Alignment::Start => pct, Alignment::Start => pct,
Alignment::End => 1.0 - pct, Alignment::End => 1.0 - pct,
} }