From 6b30e21f4ee4d21d6e549a86c6726dba399e2b03 Mon Sep 17 00:00:00 2001 From: Markus Webel Date: Sun, 6 Sep 2020 06:57:29 +0200 Subject: [PATCH] Kinetic scrolling (#20) * Fixed typo in function description * Added vertical kinetic scrolling * Checked off kinetic scrolling from TODO Co-authored-by: Markus Webel --- TODO.md | 2 +- egui/src/containers/area.rs | 2 +- egui/src/containers/scroll_area.rs | 25 ++++++++++++++++++++++++- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/TODO.md b/TODO.md index fffd75e2..a35c9975 100644 --- a/TODO.md +++ b/TODO.md @@ -18,7 +18,7 @@ TODO-list for the Egui project. If you looking for something to do, look here. * [x] Scroll-wheel input * [x] Drag background to scroll * [ ] Horizontal scrolling - * [ ] Kinetic scrolling + * [X] Kinetic scrolling * [ ] Text * [ ] Unicode * [ ] Shared mutable expanding texture map? diff --git a/egui/src/containers/area.rs b/egui/src/containers/area.rs index 4ec5f93d..cb0d81c3 100644 --- a/egui/src/containers/area.rs +++ b/egui/src/containers/area.rs @@ -32,7 +32,7 @@ impl State { } } -/// An area on the screen that can be move by dragging. +/// An area on the screen that can be moved by dragging. /// /// This forms the base of the `Window` container. #[derive(Clone, Copy, Debug)] diff --git a/egui/src/containers/scroll_area.rs b/egui/src/containers/scroll_area.rs index 105240e4..c29c622b 100644 --- a/egui/src/containers/scroll_area.rs +++ b/egui/src/containers/scroll_area.rs @@ -8,6 +8,10 @@ pub(crate) struct State { offset: Vec2, show_scroll: bool, + + /// Momentum, used for kinetic scrolling + #[cfg_attr(feature = "serde", serde(skip))] + pub vel: Vec2, } impl Default for State { @@ -15,6 +19,7 @@ impl Default for State { Self { offset: Vec2::zero(), show_scroll: false, + vel: Vec2::zero(), } } } @@ -153,8 +158,26 @@ impl Prepared { if content_is_too_small { // Drag contents to scroll (for touch screens mostly): let content_response = ui.interact(inner_rect, id.with("area"), Sense::drag()); + + let input = ui.input(); if content_response.active { - state.offset.y -= ui.input().mouse.delta.y; + state.offset.y -= input.mouse.delta.y; + state.vel = input.mouse.velocity; + } else { + let stop_speed = 20.0; // Pixels per second. + let friction_coeff = 1000.0; // Pixels per second squared. + let dt = input.unstable_dt; + + let friction = friction_coeff * dt; + if friction > state.vel.length() || state.vel.length() < stop_speed { + state.vel = Vec2::zero(); + } else { + state.vel -= friction * state.vel.normalized(); + // Offset has an inverted coordinate system compared to + // the velocity, so we subtract it instead of adding it + state.offset.y -= state.vel.y * dt; + ui.ctx().request_repaint(); + } } }