Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

scroll_with_delta doesn't work #2783

Closed
marcin-serwin opened this issue Mar 4, 2023 · 1 comment · Fixed by #4303 · May be fixed by #4412
Closed

scroll_with_delta doesn't work #2783

marcin-serwin opened this issue Mar 4, 2023 · 1 comment · Fixed by #4303 · May be fixed by #4412
Labels
bug Something is broken

Comments

@marcin-serwin
Copy link

Describe the bug

scroll_with_delta doesn't seem to work.

To Reproduce

Steps to reproduce the behavior:

  1. Create an app with eframe.
  2. Copy the scroll_with_delta example from documentation.
  3. Click Scroll down button.
  4. See that nothing happens.
use eframe::egui::{self, Vec2};

fn main() -> Result<(), eframe::Error> {
    eframe::run_native(
        "My egui App",
        eframe::NativeOptions::default(),
        Box::new(|_cc| Box::new(MyApp {})),
    )
}

struct MyApp {}

impl eframe::App for MyApp {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        egui::CentralPanel::default().show(ctx, |ui| {
            let mut scroll_delta = Vec2::ZERO;
            if ui.button("Scroll down").clicked() {
                scroll_delta.y -= 64.0; // move content up
            }
            egui::ScrollArea::vertical().show(ui, |ui| {
                ui.scroll_with_delta(scroll_delta);
                for i in 0..1000 {
                    ui.label(format!("Item {}", i));
                }
            });
        });
    }
}

Expected behavior

Content scrolls down.

Screenshots

untitled.webm

Desktop (please complete the following information):

  • OS: GNU/Linux
@marcin-serwin marcin-serwin added the bug Something is broken label Mar 4, 2023
@YgorSouza
Copy link
Contributor

YgorSouza commented Mar 4, 2023

It looks like this is the code that handles the scroll_delta:

if scrolling_enabled && ui.rect_contains_pointer(outer_rect) {
for d in 0..2 {
if has_bar[d] {
let scroll_delta = ui.ctx().frame_state(|fs| fs.scroll_delta);
let scrolling_up = state.offset[d] > 0.0 && scroll_delta[d] > 0.0;
let scrolling_down = state.offset[d] < max_offset[d] && scroll_delta[d] < 0.0;
if scrolling_up || scrolling_down {
state.offset[d] -= scroll_delta[d];
// Clear scroll delta so no parent scroll will use it.
ui.ctx().frame_state_mut(|fs| fs.scroll_delta[d] = 0.0);
state.scroll_stuck_to_end[d] = false;
}
}
}
}

It only takes the delta into account if the pointer is inside the scroll area, so the example will never work, since you have to click a button that is outside the area. If I remove this condition, it works as intended. I don't know why it is written this way, and both the code above and the scroll_with_delta method are untouched for almost a year. I also tested with the commit that originally introduced the method (676ff04), and it didn't work there either. If there is no other reason for the && ui.rect_contains_pointer(outer_rect) condition, I supposed it could just be removed and the method will be fixed. But I'll wait to see if anyone has anything to say about it, and do some tests to see if it breaks anything else.

I suspect that since the scroll_delta is set in the Context, and is therefore global to the whole UI, the idea is that if there is more than one scroll area, the one that is hovered by the mouse would be the one to use the delta. But I guess if you set it from within the show() method of the scroll area that you want to manipulate, that will not be a problem. But I'm not sure I fully understand how this is supposed to work.

Edit: actually, the && ui.rect_contains_pointer(outer_rect) is needed because this scroll_delta value is also set by the scrolling events. If we remove it, scrolling with the mouse wheel is going to affect the first scroll area that is drawn on that frame, regardless of where the pointer is. So that is not an option. I guess we have to separate the two functionalities somehow, so that the input-based scroll uses the pointer position to determine which scroll area is concerned, but the programmatic scroll affects the next scroll area to be drawn after the scroll_with_delta call.

emilk added a commit that referenced this issue May 28, 2024
…used (#4303)

<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/master/CONTRIBUTING.md)
before opening a Pull Request!

* Keep your PR:s small and focused.
* The PR title is what ends up in the changelog, so make it descriptive!
* If applicable, add a screenshot or gif.
* If it is a non-trivial addition, consider adding a demo for it to
`egui_demo_lib`, or a new example.
* Do NOT open PR:s from your `master` branch, as that makes it hard for
maintainers to add commits to your PR.
* Remember to run `cargo fmt` and `cargo cranky`.
* Open the PR as a draft until you have self-reviewed it and run
`./scripts/check.sh`.
* When you have addressed a PR comment, mark it as resolved.

Please be patient! I will review your PR, but my time is limited!
-->

This introduces the boolean field force_current_scroll_area to
InputState which will be set when scroll_with_delta is called, causing
the ScrollArea to skip the check whether it is focused and always
consume the smooth scroll delta.

* Closes #2783 
* Related to #4295

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment