Skip to content

Commit

Permalink
Update ScrollArea drag velocity when drag stopped (#5175)
Browse files Browse the repository at this point in the history
Fixes #5174.

The drag velocity was not being updated unless the cursor counted as
"dragging", which only happens when it's in motion. This effectively
guarantees that the drag velocity will never be zero, even if the cursor
is not moving, and results in spurious scroll velocity being applied
when the cursor is released.

Instead, we update the velocity only when the drag is stopped, which is
when the kinetic scrolling actually needs to begin. Note that we
immediately *apply* the scroll velocity on the same frame that we first
set it, to avoid a 1-frame gap where the scroll area doesn't move.

I believe that *not* setting `scroll_stuck_to_end` and `offset_target`
when the drag is released is the correct thing to do, as they should
apply immediately once the user stops dragging. Should we maybe clear
the drag velocity instead if `scroll_stuck_to_end` is true or
`offset_target` exists?

* Closes #5174
* [x] I have followed the instructions in the PR template
  • Loading branch information
valadaptive authored Oct 2, 2024
1 parent 24cd711 commit ac2466d
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 4 deletions.
16 changes: 12 additions & 4 deletions crates/egui/src/containers/scroll_area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -621,20 +621,28 @@ impl ScrollArea {
.interact_rect
.map(|rect| ui.interact(rect, id.with("area"), Sense::drag()));

if content_response_option.map(|response| response.dragged()) == Some(true) {
if content_response_option
.as_ref()
.is_some_and(|response| response.dragged())
{
for d in 0..2 {
if scroll_enabled[d] {
ui.input(|input| {
state.offset[d] -= input.pointer.delta()[d];
state.vel[d] = input.pointer.velocity()[d];
});
state.scroll_stuck_to_end[d] = false;
state.offset_target[d] = None;
} else {
state.vel[d] = 0.0;
}
}
} else {
// Apply the cursor velocity to the scroll area when the user releases the drag.
if content_response_option
.as_ref()
.is_some_and(|response| response.drag_stopped())
{
state.vel =
scroll_enabled.to_vec2() * ui.input(|input| input.pointer.velocity());
}
for d in 0..2 {
// Kinetic scrolling
let stop_speed = 20.0; // Pixels per second.
Expand Down
8 changes: 8 additions & 0 deletions crates/emath/src/vec2b.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::Vec2;

/// Two bools, one for each axis (X and Y).
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
Expand Down Expand Up @@ -43,6 +45,12 @@ impl Vec2b {
y: self.y || other.y,
}
}

/// Convert to a float `Vec2` where the components are 1.0 for `true` and 0.0 for `false`.
#[inline]
pub fn to_vec2(self) -> Vec2 {
Vec2::new(self.x.into(), self.y.into())
}
}

impl From<bool> for Vec2b {
Expand Down

0 comments on commit ac2466d

Please sign in to comment.