diff options
Diffstat (limited to '')
| -rw-r--r-- | native/src/widget/operation/scrollable.rs | 9 | ||||
| -rw-r--r-- | native/src/widget/scrollable.rs | 94 | 
2 files changed, 56 insertions, 47 deletions
diff --git a/native/src/widget/operation/scrollable.rs b/native/src/widget/operation/scrollable.rs index 62f4c91e..f947344d 100644 --- a/native/src/widget/operation/scrollable.rs +++ b/native/src/widget/operation/scrollable.rs @@ -64,15 +64,6 @@ pub fn scroll_to<T>(target: Id, offset: AbsoluteOffset) -> impl Operation<T> {      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 { diff --git a/native/src/widget/scrollable.rs b/native/src/widget/scrollable.rs index eedddfd0..c66a166b 100644 --- a/native/src/widget/scrollable.rs +++ b/native/src/widget/scrollable.rs @@ -15,9 +15,7 @@ use crate::{  };  pub use iced_style::scrollable::StyleSheet; -pub use operation::scrollable::{ -    AbsoluteOffset, CurrentOffset, RelativeOffset, -}; +pub use operation::scrollable::{AbsoluteOffset, RelativeOffset};  pub mod style {      //! The styles of a [`Scrollable`]. @@ -40,7 +38,7 @@ where      vertical: Properties,      horizontal: Option<Properties>,      content: Element<'a, Message, Renderer>, -    on_scroll: Option<Box<dyn Fn(CurrentOffset) -> Message + 'a>>, +    on_scroll: Option<Box<dyn Fn(Viewport) -> Message + 'a>>,      style: <Renderer::Theme as StyleSheet>::Style,  } @@ -95,11 +93,8 @@ where      /// Sets a function to call when the [`Scrollable`] is scrolled.      /// -    /// The function takes the [`CurrentOffset`] of the [`Scrollable`] -    pub fn on_scroll( -        mut self, -        f: impl Fn(CurrentOffset) -> Message + 'a, -    ) -> Self { +    /// The function takes the [`Viewport`] of the [`Scrollable`] +    pub fn on_scroll(mut self, f: impl Fn(Viewport) -> Message + 'a) -> Self {          self.on_scroll = Some(Box::new(f));          self      } @@ -437,7 +432,7 @@ pub fn update<Message>(      shell: &mut Shell<'_, Message>,      vertical: &Properties,      horizontal: Option<&Properties>, -    on_scroll: &Option<Box<dyn Fn(CurrentOffset) -> Message + '_>>, +    on_scroll: &Option<Box<dyn Fn(Viewport) -> Message + '_>>,      update_content: impl FnOnce(          Event,          Layout<'_>, @@ -897,7 +892,7 @@ pub fn draw<Renderer>(  fn notify_on_scroll<Message>(      state: &mut State, -    on_scroll: &Option<Box<dyn Fn(CurrentOffset) -> Message + '_>>, +    on_scroll: &Option<Box<dyn Fn(Viewport) -> Message + '_>>,      bounds: Rectangle,      content_bounds: Rectangle,      shell: &mut Shell<'_, Message>, @@ -909,39 +904,29 @@ fn notify_on_scroll<Message>(              return;          } -        let absolute_x = -            state.offset_x.absolute(bounds.width, content_bounds.width); -        let relative_x = absolute_x / (content_bounds.width - bounds.width); - -        let absolute_y = state -            .offset_y -            .absolute(bounds.height, content_bounds.height); -        let relative_y = absolute_y / (content_bounds.height - bounds.height); - -        let absolute = AbsoluteOffset { -            x: absolute_x, -            y: absolute_y, -        }; -        let relative = RelativeOffset { -            x: relative_x, -            y: relative_y, +        let viewport = Viewport { +            offset_x: state.offset_x, +            offset_y: state.offset_y, +            bounds, +            content_bounds,          }; -        // Don't publish redundant offsets to shell -        if let Some(prev_relative) = state.last_notified { +        // Don't publish redundant viewports to shell +        if let Some(last_notified) = state.last_notified { +            let prev = last_notified.relative_offset(); +            let curr = viewport.relative_offset(); +              let unchanged = |a: f32, b: f32| {                  (a - b).abs() <= f32::EPSILON || (a.is_nan() && b.is_nan())              }; -            if unchanged(prev_relative.x, relative.x) -                && unchanged(prev_relative.y, relative.y) -            { +            if unchanged(prev.x, curr.x) && unchanged(prev.y, curr.y) {                  return;              }          } -        shell.publish(on_scroll(CurrentOffset { absolute, relative })); -        state.last_notified = Some(relative); +        shell.publish(on_scroll(viewport)); +        state.last_notified = Some(viewport);      }  } @@ -954,7 +939,7 @@ pub struct State {      offset_x: Offset,      x_scroller_grabbed_at: Option<f32>,      keyboard_modifiers: keyboard::Modifiers, -    last_notified: Option<RelativeOffset>, +    last_notified: Option<Viewport>,  }  impl Default for State { @@ -988,18 +973,51 @@ enum Offset {  }  impl Offset { -    fn absolute(self, window: f32, content: f32) -> f32 { +    fn absolute(self, viewport: f32, content: f32) -> f32 {          match self {              Offset::Absolute(absolute) => { -                absolute.min((content - window).max(0.0)) +                absolute.min((content - viewport).max(0.0))              }              Offset::Relative(percentage) => { -                ((content - window) * percentage).max(0.0) +                ((content - viewport) * percentage).max(0.0)              }          }      }  } +/// The current [`Viewport`] of the [`Scrollable`]. +#[derive(Debug, Clone, Copy)] +pub struct Viewport { +    offset_x: Offset, +    offset_y: Offset, +    bounds: Rectangle, +    content_bounds: Rectangle, +} + +impl Viewport { +    /// Returns the [`AbsoluteOffset`] of the current [`Viewport`]. +    pub fn absolute_offset(&self) -> AbsoluteOffset { +        let x = self +            .offset_x +            .absolute(self.bounds.width, self.content_bounds.width); +        let y = self +            .offset_y +            .absolute(self.bounds.height, self.content_bounds.height); + +        AbsoluteOffset { x, y } +    } + +    /// Returns the [`RelativeOffset`] of the current [`Viewport`]. +    pub fn relative_offset(&self) -> RelativeOffset { +        let AbsoluteOffset { x, y } = self.absolute_offset(); + +        let x = x / (self.content_bounds.width - self.bounds.width); +        let y = y / (self.content_bounds.height - self.bounds.height); + +        RelativeOffset { x, y } +    } +} +  impl State {      /// Creates a new [`State`] with the scrollbar(s) at the beginning.      pub fn new() -> Self {  | 
