From 432a84be04cfaea976ccbb8d80ee44fe2c63f67e Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Sun, 6 Oct 2024 09:44:37 -0700 Subject: [PATCH] Scroll::preserve_max_scroll --- CHANGELOG.md | 2 ++ src/widgets/scroll.rs | 26 +++++++++++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74f292d10..32693d27b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -217,6 +217,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Choosing one or more folders/directories - `DynamicGuard::unlocked` executes a closure while the guard is temporarily unlocked. +- `Scroll::preserve_max_scroll` controls whether the scroll view automatically + scrolls when currently scrolled to the maximum and its child grows. [139]: https://github.com/khonsulabs/cushy/issues/139 diff --git a/src/widgets/scroll.rs b/src/widgets/scroll.rs index 41bf7dda5..e86ba15b1 100644 --- a/src/widgets/scroll.rs +++ b/src/widgets/scroll.rs @@ -13,7 +13,7 @@ use crate::animation::{AnimationHandle, AnimationTarget, IntoAnimate, Spawn, Zer use crate::context::{AsEventContext, EventContext, LayoutContext}; use crate::styles::components::{EasingIn, EasingOut, LineHeight}; use crate::styles::Dimension; -use crate::value::{Destination, Dynamic, Source}; +use crate::value::{Destination, Dynamic, IntoValue, Source, Value}; use crate::widget::{EventHandling, MakeWidget, Widget, WidgetRef, HANDLED, IGNORED}; use crate::window::DeviceId; use crate::ConstraintLimit; @@ -26,6 +26,7 @@ pub struct Scroll { control_size: Size, scroll: Dynamic>, enabled: Point, + preserve_max_scroll: Value, max_scroll: Dynamic>, scrollbar_opacity: Dynamic, scrollbar_opacity_animation: OpacityAnimationState, @@ -64,6 +65,7 @@ impl Scroll { bar_width: Px::default(), line_height: Px::default(), drag: DragInfo::default(), + preserve_max_scroll: Value::Constant(true), } } @@ -84,6 +86,18 @@ impl Scroll { Self::construct(contents, Point::new(false, true)) } + /// Sets whether the scroll view will stay scrolled to the maximum when a + /// child is resized. + /// + /// When enabled, this setting allows the scroll view to remain scrolled to + /// the bottom or to the right when its contents grow. The default value for + /// this setting is `true`. + #[must_use] + pub fn preserve_max_scroll(mut self, preserve: impl IntoValue) -> Self { + self.preserve_max_scroll = preserve.into_value(); + self + } + fn constrained_scroll(scroll: Point, max_scroll: Point) -> Point { scroll.max(max_scroll).min(Point::default()) } @@ -266,16 +280,18 @@ impl Widget for Scroll { || self.control_size.width != control_size.width { self.content_size.width = new_content_size.width; - let scroll_pct = scroll.x.into_float() / current_max_scroll.x.into_float(); - scroll.x = max_scroll_x * scroll_pct; + if self.preserve_max_scroll.get() && scroll.x == current_max_scroll.x { + scroll.x = max_scroll_x; + } } if self.content_size.height != new_content_size.height || self.control_size.height != control_size.height { self.content_size.height = new_content_size.height; - let scroll_pct = scroll.y.into_float() / current_max_scroll.y.into_float(); - scroll.y = max_scroll_y * scroll_pct; + if self.preserve_max_scroll.get() && scroll.y == current_max_scroll.y { + scroll.y = max_scroll_y; + } } // Set the current scroll, but prevent immediately triggering // invalidate.