From 11287c882e23e1f3081d06bf5ff3e99a02ef030a Mon Sep 17 00:00:00 2001 From: Cory Forsstrom Date: Wed, 12 Jul 2023 16:30:12 -0700 Subject: [PATCH 1/3] Expose methods to change viewport alignment --- widget/src/scrollable.rs | 59 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index 88746ac4f2..3f49584cf0 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -554,7 +554,14 @@ pub fn update( state.scroll(delta, direction, bounds, content_bounds); - notify_on_scroll(state, on_scroll, bounds, content_bounds, shell); + notify_on_scroll( + state, + on_scroll, + bounds, + content_bounds, + direction, + shell, + ); return event::Status::Captured; } @@ -592,6 +599,7 @@ pub fn update( on_scroll, bounds, content_bounds, + direction, shell, ); } @@ -637,6 +645,7 @@ pub fn update( on_scroll, bounds, content_bounds, + direction, shell, ); @@ -672,6 +681,7 @@ pub fn update( on_scroll, bounds, content_bounds, + direction, shell, ); } @@ -712,6 +722,7 @@ pub fn update( on_scroll, bounds, content_bounds, + direction, shell, ); } @@ -747,6 +758,7 @@ pub fn update( on_scroll, bounds, content_bounds, + direction, shell, ); @@ -962,6 +974,7 @@ fn notify_on_scroll( on_scroll: &Option Message + '_>>, bounds: Rectangle, content_bounds: Rectangle, + direction: Direction, shell: &mut Shell<'_, Message>, ) { if let Some(on_scroll) = on_scroll { @@ -971,11 +984,23 @@ fn notify_on_scroll( return; } + 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 viewport = Viewport { offset_x: state.offset_x, offset_y: state.offset_y, bounds, content_bounds, + vertical_alignment, + horizontal_alignment, }; // Don't publish redundant viewports to shell @@ -1080,6 +1105,8 @@ pub struct Viewport { offset_y: Offset, bounds: Rectangle, content_bounds: Rectangle, + vertical_alignment: Alignment, + horizontal_alignment: Alignment, } impl Viewport { @@ -1104,6 +1131,36 @@ impl Viewport { RelativeOffset { x, y } } + + /// Returns a new [`Viewport`] with the supplied vertical [`Alignment`]. + pub fn with_vertical_alignment(self, alignment: Alignment) -> Self { + if self.vertical_alignment != alignment { + let relative = 1.0 - self.relative_offset().y; + + Self { + offset_y: Offset::Relative(relative), + vertical_alignment: alignment, + ..self + } + } else { + self + } + } + + /// Returns a new [`Viewport`] with the supplied horizontal [`Alignment`]. + pub fn with_horizontal_alignment(self, alignment: Alignment) -> Self { + if self.horizontal_alignment != alignment { + let relative = 1.0 - self.relative_offset().x; + + Self { + offset_x: Offset::Relative(relative), + horizontal_alignment: alignment, + ..self + } + } else { + self + } + } } impl State { From a9987cb32e4d65b83f134ba54f51dffe16e93a50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 13 Jul 2023 02:53:45 +0200 Subject: [PATCH 2/3] Introduce `absolute_offset_reversed` to `scrollable::Viewport` --- widget/src/scrollable.rs | 75 +++++++++------------------------------- 1 file changed, 17 insertions(+), 58 deletions(-) diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index 3f49584cf0..5cd9453834 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -554,14 +554,7 @@ pub fn update( state.scroll(delta, direction, bounds, content_bounds); - notify_on_scroll( - state, - on_scroll, - bounds, - content_bounds, - direction, - shell, - ); + notify_on_scroll(state, on_scroll, bounds, content_bounds, shell); return event::Status::Captured; } @@ -599,7 +592,6 @@ pub fn update( on_scroll, bounds, content_bounds, - direction, shell, ); } @@ -645,7 +637,6 @@ pub fn update( on_scroll, bounds, content_bounds, - direction, shell, ); @@ -681,7 +672,6 @@ pub fn update( on_scroll, bounds, content_bounds, - direction, shell, ); } @@ -722,7 +712,6 @@ pub fn update( on_scroll, bounds, content_bounds, - direction, shell, ); } @@ -758,7 +747,6 @@ pub fn update( on_scroll, bounds, content_bounds, - direction, shell, ); @@ -974,7 +962,6 @@ fn notify_on_scroll( on_scroll: &Option Message + '_>>, bounds: Rectangle, content_bounds: Rectangle, - direction: Direction, shell: &mut Shell<'_, Message>, ) { if let Some(on_scroll) = on_scroll { @@ -984,23 +971,11 @@ fn notify_on_scroll( return; } - 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 viewport = Viewport { offset_x: state.offset_x, offset_y: state.offset_y, bounds, content_bounds, - vertical_alignment, - horizontal_alignment, }; // Don't publish redundant viewports to shell @@ -1105,8 +1080,6 @@ pub struct Viewport { offset_y: Offset, bounds: Rectangle, content_bounds: Rectangle, - vertical_alignment: Alignment, - horizontal_alignment: Alignment, } impl Viewport { @@ -1122,6 +1095,22 @@ impl Viewport { AbsoluteOffset { x, y } } + /// Returns the [`AbsoluteOffset`] of the current [`Viewport`], but with its + /// alignment reversed. + /// + /// This method can be useful to switch the alignment of a [`Scrollable`] + /// while maintaining its scrolling position. + pub fn absolute_offset_reversed(&self) -> AbsoluteOffset { + let AbsoluteOffset { x, y } = self.absolute_offset(); + + AbsoluteOffset { + x: ((self.content_bounds.width - self.bounds.width).max(0.0) - x) + .max(0.0), + y: ((self.content_bounds.height - self.bounds.height).max(0.0) - y) + .max(0.0), + } + } + /// Returns the [`RelativeOffset`] of the current [`Viewport`]. pub fn relative_offset(&self) -> RelativeOffset { let AbsoluteOffset { x, y } = self.absolute_offset(); @@ -1131,36 +1120,6 @@ impl Viewport { RelativeOffset { x, y } } - - /// Returns a new [`Viewport`] with the supplied vertical [`Alignment`]. - pub fn with_vertical_alignment(self, alignment: Alignment) -> Self { - if self.vertical_alignment != alignment { - let relative = 1.0 - self.relative_offset().y; - - Self { - offset_y: Offset::Relative(relative), - vertical_alignment: alignment, - ..self - } - } else { - self - } - } - - /// Returns a new [`Viewport`] with the supplied horizontal [`Alignment`]. - pub fn with_horizontal_alignment(self, alignment: Alignment) -> Self { - if self.horizontal_alignment != alignment { - let relative = 1.0 - self.relative_offset().x; - - Self { - offset_x: Offset::Relative(relative), - horizontal_alignment: alignment, - ..self - } - } else { - self - } - } } impl State { From d36758405789d6a305d978eefb46a1ca90d141d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 13 Jul 2023 03:01:53 +0200 Subject: [PATCH 3/3] Avoid redundant `max` in `absolute_offset_reversed` I believe `Offset::absolute` guarantees the offset never exceeds the maximum scrolling boundaries already. --- widget/src/scrollable.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index 5cd9453834..e0aeeebd58 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -1104,10 +1104,8 @@ impl Viewport { let AbsoluteOffset { x, y } = self.absolute_offset(); AbsoluteOffset { - x: ((self.content_bounds.width - self.bounds.width).max(0.0) - x) - .max(0.0), - y: ((self.content_bounds.height - self.bounds.height).max(0.0) - y) - .max(0.0), + x: (self.content_bounds.width - self.bounds.width).max(0.0) - x, + y: (self.content_bounds.height - self.bounds.height).max(0.0) - y, } }