diff options
| author | 2023-04-14 13:32:44 -0700 | |
|---|---|---|
| committer | 2023-04-14 13:32:44 -0700 | |
| commit | b623f280ed43b04cef16a82de4cdf13497b5d63e (patch) | |
| tree | 278327c128ecc8716f3ad2b69c857363c548119a /native/src | |
| parent | 4b05f42fd6d18bf572b772dd60d6a4309ea5f343 (diff) | |
| download | iced-b623f280ed43b04cef16a82de4cdf13497b5d63e.tar.gz iced-b623f280ed43b04cef16a82de4cdf13497b5d63e.tar.bz2 iced-b623f280ed43b04cef16a82de4cdf13497b5d63e.zip  | |
Add `scroll_to` operation for absolute scroll
Diffstat (limited to '')
| -rw-r--r-- | native/src/widget/operation/scrollable.rs | 50 | ||||
| -rw-r--r-- | native/src/widget/scrollable.rs | 55 | 
2 files changed, 86 insertions, 19 deletions
diff --git a/native/src/widget/operation/scrollable.rs b/native/src/widget/operation/scrollable.rs index 3b20631f..62f4c91e 100644 --- a/native/src/widget/operation/scrollable.rs +++ b/native/src/widget/operation/scrollable.rs @@ -5,6 +5,9 @@ use crate::widget::{Id, Operation};  pub trait Scrollable {      /// Snaps the scroll of the widget to the given `percentage` along the horizontal & vertical axis.      fn snap_to(&mut self, offset: RelativeOffset); + +    /// Scroll the widget to the given [`AbsoluteOffset`] along the horizontal & vertical axis. +    fn scroll_to(&mut self, offset: AbsoluteOffset);  }  /// Produces an [`Operation`] that snaps the widget with the given [`Id`] to @@ -34,7 +37,52 @@ pub fn snap_to<T>(target: Id, offset: RelativeOffset) -> impl Operation<T> {      SnapTo { target, offset }  } -/// The amount of offset in each direction of a [`Scrollable`]. +/// Produces an [`Operation`] that scrolls the widget with the given [`Id`] to +/// the provided [`AbsoluteOffset`]. +pub fn scroll_to<T>(target: Id, offset: AbsoluteOffset) -> impl Operation<T> { +    struct ScrollTo { +        target: Id, +        offset: AbsoluteOffset, +    } + +    impl<T> Operation<T> for ScrollTo { +        fn container( +            &mut self, +            _id: Option<&Id>, +            operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>), +        ) { +            operate_on_children(self) +        } + +        fn scrollable(&mut self, state: &mut dyn Scrollable, id: Option<&Id>) { +            if Some(&self.target) == id { +                state.scroll_to(self.offset); +            } +        } +    } + +    ScrollTo { target, offset } +} + +/// The current absolute & relative offset of a [`Scrollable`] +#[derive(Debug, Clone, Copy, PartialEq, Default)] +pub struct CurrentOffset { +    /// The [`AbsoluteOffset`] of a [`Scrollable`] +    pub absolute: AbsoluteOffset, +    /// The [`RelativeOffset`] of a [`Scrollable`] +    pub relative: RelativeOffset, +} + +/// The amount of absolute offset in each direction of a [`Scrollable`]. +#[derive(Debug, Clone, Copy, PartialEq, Default)] +pub struct AbsoluteOffset { +    /// The amount of horizontal offset +    pub x: f32, +    /// The amount of vertical offset +    pub y: f32, +} + +/// The amount of relative offset in each direction of a [`Scrollable`].  ///  /// A value of `0.0` means start, while `1.0` means end.  #[derive(Debug, Clone, Copy, PartialEq, Default)] diff --git a/native/src/widget/scrollable.rs b/native/src/widget/scrollable.rs index 78dcdca2..eedddfd0 100644 --- a/native/src/widget/scrollable.rs +++ b/native/src/widget/scrollable.rs @@ -15,7 +15,9 @@ use crate::{  };  pub use iced_style::scrollable::StyleSheet; -pub use operation::scrollable::RelativeOffset; +pub use operation::scrollable::{ +    AbsoluteOffset, CurrentOffset, RelativeOffset, +};  pub mod style {      //! The styles of a [`Scrollable`]. @@ -38,7 +40,7 @@ where      vertical: Properties,      horizontal: Option<Properties>,      content: Element<'a, Message, Renderer>, -    on_scroll: Option<Box<dyn Fn(RelativeOffset) -> Message + 'a>>, +    on_scroll: Option<Box<dyn Fn(CurrentOffset) -> Message + 'a>>,      style: <Renderer::Theme as StyleSheet>::Style,  } @@ -93,11 +95,10 @@ where      /// Sets a function to call when the [`Scrollable`] is scrolled.      /// -    /// The function takes the new relative x & y offset of the [`Scrollable`] -    /// (e.g. `0` means beginning, while `1` means end). +    /// The function takes the [`CurrentOffset`] of the [`Scrollable`]      pub fn on_scroll(          mut self, -        f: impl Fn(RelativeOffset) -> Message + 'a, +        f: impl Fn(CurrentOffset) -> Message + 'a,      ) -> Self {          self.on_scroll = Some(Box::new(f));          self @@ -436,7 +437,7 @@ pub fn update<Message>(      shell: &mut Shell<'_, Message>,      vertical: &Properties,      horizontal: Option<&Properties>, -    on_scroll: &Option<Box<dyn Fn(RelativeOffset) -> Message + '_>>, +    on_scroll: &Option<Box<dyn Fn(CurrentOffset) -> Message + '_>>,      update_content: impl FnOnce(          Event,          Layout<'_>, @@ -896,7 +897,7 @@ pub fn draw<Renderer>(  fn notify_on_scroll<Message>(      state: &mut State, -    on_scroll: &Option<Box<dyn Fn(RelativeOffset) -> Message + '_>>, +    on_scroll: &Option<Box<dyn Fn(CurrentOffset) -> Message + '_>>,      bounds: Rectangle,      content_bounds: Rectangle,      shell: &mut Shell<'_, Message>, @@ -908,31 +909,39 @@ fn notify_on_scroll<Message>(              return;          } -        let x = state.offset_x.absolute(bounds.width, content_bounds.width) -            / (content_bounds.width - bounds.width); +        let absolute_x = +            state.offset_x.absolute(bounds.width, content_bounds.width); +        let relative_x = absolute_x / (content_bounds.width - bounds.width); -        let y = state +        let absolute_y = state              .offset_y -            .absolute(bounds.height, content_bounds.height) -            / (content_bounds.height - bounds.height); +            .absolute(bounds.height, content_bounds.height); +        let relative_y = absolute_y / (content_bounds.height - bounds.height); -        let new_offset = RelativeOffset { x, y }; +        let absolute = AbsoluteOffset { +            x: absolute_x, +            y: absolute_y, +        }; +        let relative = RelativeOffset { +            x: relative_x, +            y: relative_y, +        };          // Don't publish redundant offsets to shell -        if let Some(prev_offset) = state.last_notified { +        if let Some(prev_relative) = state.last_notified {              let unchanged = |a: f32, b: f32| {                  (a - b).abs() <= f32::EPSILON || (a.is_nan() && b.is_nan())              }; -            if unchanged(prev_offset.x, new_offset.x) -                && unchanged(prev_offset.y, new_offset.y) +            if unchanged(prev_relative.x, relative.x) +                && unchanged(prev_relative.y, relative.y)              {                  return;              }          } -        shell.publish(on_scroll(new_offset)); -        state.last_notified = Some(new_offset); +        shell.publish(on_scroll(CurrentOffset { absolute, relative })); +        state.last_notified = Some(relative);      }  } @@ -966,6 +975,10 @@ impl operation::Scrollable for State {      fn snap_to(&mut self, offset: RelativeOffset) {          State::snap_to(self, offset);      } + +    fn scroll_to(&mut self, offset: AbsoluteOffset) { +        State::scroll_to(self, offset) +    }  }  #[derive(Debug, Clone, Copy)] @@ -1052,6 +1065,12 @@ impl State {          self.offset_y = Offset::Relative(offset.y.clamp(0.0, 1.0));      } +    /// Scroll to the provided [`AbsoluteOffset`]. +    pub fn scroll_to(&mut self, offset: AbsoluteOffset) { +        self.offset_x = Offset::Absolute(offset.x.max(0.0)); +        self.offset_y = Offset::Absolute(offset.y.max(0.0)); +    } +      /// Unsnaps the current scroll position, if snapped, given the bounds of the      /// [`Scrollable`] and its contents.      pub fn unsnap(&mut self, bounds: Rectangle, content_bounds: Rectangle) {  | 
