summaryrefslogtreecommitdiffstats
path: root/native
diff options
context:
space:
mode:
authorLibravatar Cory Forsstrom <cforsstrom18@gmail.com>2023-04-14 13:32:44 -0700
committerLibravatar Cory Forsstrom <cforsstrom18@gmail.com>2023-04-14 13:32:44 -0700
commitb623f280ed43b04cef16a82de4cdf13497b5d63e (patch)
tree278327c128ecc8716f3ad2b69c857363c548119a /native
parent4b05f42fd6d18bf572b772dd60d6a4309ea5f343 (diff)
downloadiced-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.rs50
-rw-r--r--native/src/widget/scrollable.rs55
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) {