emilk / egui

egui: an easy-to-use immediate mode GUI in Rust that runs on both web and native
https://www.egui.rs/
Apache License 2.0
20.64k stars 1.49k forks source link

scrollwheel acceleration carries into ScrollArea when pointer is outside during scrolling #4653

Open j-n-f opened 2 weeks ago

j-n-f commented 2 weeks ago

Describe the bug A ScrollArea will scroll if the mouse cursor moves into a ScrollArea after the mousewheel has finished being physically scrolled.

To Reproduce Steps to reproduce the behavior:

  1. Create a ScrollArea with some space around it
  2. rotate the scroll wheel on your mouse hard/fast while the pointer is over the window but outside of the ScrollArea
  3. With the scroll wheel on the mouse stationary, very quickly move the pointer into the ScrollArea
  4. Observe: the scroll wheel on the mouse isn't being moved, but the ScrollArea is moving (in the same direction you scrolled, decelerating)

Expected behavior A ScrollArea shouldn't react to events which didn't originate inside it.

Desktop (please complete the following information):

Additional Context

I looked through system/mouse/accessibility settings to see if this was happening outside egui (or other libraries it uses), but I didn't find anything.

rustbasic commented 2 weeks ago

It will probably be fixed in the next version. It has been modified from the master version.

j-n-f commented 2 weeks ago

@rustbasic I just gave 814ad078 on master a try, I still see the issue.

Looking through the code, it seems like the logic is something like:

  1. If the pointer is over the outer rect (is_hovering_outer_rect in Prepared::end())
  2. Take InputState::smooth_scroll_delta and apply it (regardless of where the pointer was when the scrolling started/stopped)

I added the following to the bottom of my UI to debug:

let delta = ui.ctx().input(|r| {
    r.smooth_scroll_delta
});
ui.label(format!("{:?}", delta));

And it does seem to be doing what I think it is.

I think to fix this we would have to do something like:

  1. See if the pointer is over the outer rect
  2. Take InputState::raw_scroll_delta (instead of the smoothed value, which seems to apply globally to the whole UI), add it to an accumulator
  3. Apply smoothing to the accumulated value after we know that the raw scroll originated inside the outer rect

I can put together a PR when I get some time, but I'm wondering if anyone else has thoughts on it. I think the expectation I have would imply that the same behavior is expected for other widgets as well. If that's the case another approach might be warranted.

If there's other work to "scope" input events to widgets/components then I'd consider this ticket a duplicate and close it in favor of the other issue.

rustbasic commented 2 weeks ago

It's best to wait for emilk's response regarding whether they'd like you to submit a Pull Request. Alternatively, you can try fixing the issue and submitting a Pull Request yourself.