Added support for fling.
This commit is contained in:
parent
858237266c
commit
24c906ca9f
95
src/lib.rs
95
src/lib.rs
|
|
@ -25,11 +25,13 @@ impl Plugin for ScrollViewPlugin {
|
||||||
create_scroll_view,
|
create_scroll_view,
|
||||||
update_size,
|
update_size,
|
||||||
scroll_events,
|
scroll_events,
|
||||||
|
fling_update,
|
||||||
scroll_update,
|
scroll_update,
|
||||||
)
|
)
|
||||||
.chain(),
|
.chain(),
|
||||||
)
|
)
|
||||||
.add_observer(on_drag);
|
.add_observer(on_drag)
|
||||||
|
.add_observer(on_drag_end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,12 +42,21 @@ pub struct ScrollView {
|
||||||
/// Field which control speed of the scrolling.
|
/// Field which control speed of the scrolling.
|
||||||
/// Could be negative number to implement invert scroll
|
/// Could be negative number to implement invert scroll
|
||||||
pub scroll_speed: f32,
|
pub scroll_speed: f32,
|
||||||
|
/// Amount of friction to apply to slow down the fling
|
||||||
|
pub friction: f32,
|
||||||
|
/// Current vertical velocity
|
||||||
|
velocity: f32,
|
||||||
|
/// Drag delta for fling
|
||||||
|
drag_delta: Option<DragDelta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ScrollView {
|
impl Default for ScrollView {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
scroll_speed: 1200.0,
|
scroll_speed: 1200.0,
|
||||||
|
friction: 4.2,
|
||||||
|
velocity: 0.0,
|
||||||
|
drag_delta: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -148,12 +159,39 @@ fn update_size(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Reflect)]
|
||||||
|
struct DragDelta {
|
||||||
|
/// Sum of drag deltas since last reset
|
||||||
|
pub diff: Vec2,
|
||||||
|
/// Last time when drag_delta was added to velocity and reset
|
||||||
|
pub time: f32,
|
||||||
|
}
|
||||||
|
|
||||||
fn on_drag(
|
fn on_drag(
|
||||||
mut drag: Trigger<Pointer<Drag>>,
|
mut drag: Trigger<Pointer<Drag>>,
|
||||||
mut q: Query<&Children, With<ScrollView>>,
|
mut q: Query<(&mut ScrollView, &mut Children)>,
|
||||||
mut content_q: Query<&mut ScrollableContent>,
|
mut content_q: Query<&mut ScrollableContent>,
|
||||||
|
time: Res<Time>,
|
||||||
) {
|
) {
|
||||||
if let Ok(children) = q.get_mut(drag.target()) {
|
if let Ok((mut view, children)) = q.get_mut(drag.target()) {
|
||||||
|
if let Some(mut delta) = view.drag_delta.take() {
|
||||||
|
let elapsed = time.elapsed_secs() - delta.time;
|
||||||
|
if elapsed <= 0. {
|
||||||
|
delta.diff += drag.delta;
|
||||||
|
view.drag_delta = Some(delta);
|
||||||
|
} else {
|
||||||
|
view.velocity = (view.velocity + delta.diff.y / elapsed) / 2.0;
|
||||||
|
view.drag_delta = Some(DragDelta {
|
||||||
|
diff: Vec2::new(0., 0.),
|
||||||
|
time: time.elapsed_secs(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
view.drag_delta = Some(DragDelta {
|
||||||
|
diff: drag.delta,
|
||||||
|
time: time.elapsed_secs(),
|
||||||
|
});
|
||||||
|
}
|
||||||
for child in children.iter() {
|
for child in children.iter() {
|
||||||
let Ok(mut scroll) = content_q.get_mut(child) else {
|
let Ok(mut scroll) = content_q.get_mut(child) else {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -164,6 +202,16 @@ fn on_drag(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_drag_end(
|
||||||
|
mut drag: Trigger<Pointer<DragEnd>>,
|
||||||
|
mut q_view: Query<&mut ScrollView>,
|
||||||
|
) {
|
||||||
|
if let Ok(mut view) = q_view.get_mut(drag.target()) {
|
||||||
|
view.drag_delta = None;
|
||||||
|
drag.propagate(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn scroll_events(
|
fn scroll_events(
|
||||||
mut scroll_evr: EventReader<MouseWheel>,
|
mut scroll_evr: EventReader<MouseWheel>,
|
||||||
mut q: Query<(&Children, &Interaction, &ScrollView), With<ScrollView>>,
|
mut q: Query<(&Children, &Interaction, &ScrollView), With<ScrollView>>,
|
||||||
|
|
@ -200,3 +248,44 @@ fn scroll_update(mut q: Query<(&ScrollableContent, &mut Node), Changed<Scrollabl
|
||||||
style.top = Val::Px(scroll.pos_y);
|
style.top = Val::Px(scroll.pos_y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fling_update(
|
||||||
|
mut q: Query<(&Children, &mut ScrollView)>,
|
||||||
|
mut content_q: Query<&mut ScrollableContent>,
|
||||||
|
time: Res<Time>,
|
||||||
|
) {
|
||||||
|
for (children, mut view) in q.iter_mut() {
|
||||||
|
if view.drag_delta.is_some() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if view.velocity.abs() > 1. {
|
||||||
|
for child in children.iter() {
|
||||||
|
let Ok(mut scroll) = content_q.get_mut(child) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let (position, _) = calc_position_and_velocity(
|
||||||
|
scroll.pos_y,
|
||||||
|
view.velocity,
|
||||||
|
-view.friction,
|
||||||
|
time.delta_secs(),
|
||||||
|
);
|
||||||
|
scroll.pos_y = position.clamp(-scroll.max_scroll, 0.);
|
||||||
|
}
|
||||||
|
view.velocity = calc_position_and_velocity(
|
||||||
|
0.,
|
||||||
|
view.velocity,
|
||||||
|
-view.friction,
|
||||||
|
time.delta_secs(),
|
||||||
|
).1;
|
||||||
|
} else {
|
||||||
|
view.velocity = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calc_position_and_velocity(position: f32, velocity: f32, friction: f32, delta_t: f32) -> (f32, f32) {
|
||||||
|
(
|
||||||
|
position - velocity / friction + velocity / friction * (friction * delta_t).exp(),
|
||||||
|
velocity * (delta_t * friction).exp(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue