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

Basic Smooth Scrolling Example #8391

Open
Willy-JL opened this issue Feb 12, 2025 · 5 comments
Open

Basic Smooth Scrolling Example #8391

Willy-JL opened this issue Feb 12, 2025 · 5 comments

Comments

@Willy-JL
Copy link

Willy-JL commented Feb 12, 2025

Version/Branch of Dear ImGui:

Version 1.91.8, Branch: master

Back-ends:

imgui_impl_sdl3.cpp + imgui_impl_opengl3.cpp

Compiler, OS:

Linux + Clang 19.1.7

Details:

I found a workaround for smooth scrolling without modifying ImGui code, so I thought I'd share it here for anyone looking for a way to do this. It's a very simple and dumb way to do it, I am not proposing this be added to ImGui itself of course, but it works well enough for my needs so maybe others will find it useful too.

Screenshots/Video:

2025-02-12-04.50.06.148490094.mp4

Minimal, Complete and Verifiable Example code:

Parts marked as // ... indicate sections of code that aren't relevant to the logic of this workaround, you can refer to the complete ImGui backends examples and slot in this code where relevant.

// ... Your main loop

ImGuiIO& io = ImGui::GetIO();
const float scroll_multiplier = 2.0f;
const float scroll_smoothing = 8.0f;
static ImVec2 scroll_energy = ImVec2(0.0f, 0.0f);

SDL_Event event;
while (SDL_PollEvent(&event)) {
    if(event.type == SDL_EVENT_MOUSE_WHEEL && event.window.windowID == SDL_GetWindowID(window)) {
        // Handle wheel events locally to apply smooth scrolling
        event.wheel.x *= scroll_multiplier;
        event.wheel.y *= scroll_multiplier;
        // Immediately stop if direction changes
        if(scroll_energy.x * event.wheel.x < 0.0f) {
            scroll_energy.x = 0.0f;
        }
        if(scroll_energy.y * event.wheel.y < 0.0f) {
            scroll_energy.y = 0.0f;
        }
        scroll_energy.x += event.wheel.x;
        scroll_energy.y += event.wheel.y;
    } else {
        ImGui_ImplSDL3_ProcessEvent(&event);
    }

    // ... Handle close events if relevant
}

// ...

// Apply smooth scrolling (MUST be before ImGui::NewFrame())
ImVec2 scroll_now = ImVec2(0.0f, 0.0f);
if(std::abs(scroll_energy.x) > 0.01f) {
    scroll_now.x = scroll_energy.x * io.DeltaTime * scroll_smoothing;
    scroll_energy.x -= scroll_now.x;
} else {
    // Cutoff smoothing when it's basically stopped
    scroll_energy.x = 0.0f;
}
if(std::abs(scroll_energy.y) > 0.01f) {
    scroll_now.y = scroll_energy.y * io.DeltaTime * scroll_smoothing;
    scroll_energy.y -= scroll_now.y;
} else {
    // Cutoff smoothing when it's basically stopped
    scroll_energy.y = 0.0f;
}
io.MouseWheel = scroll_now.y;
io.MouseWheelH = -scroll_now.x;

ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplSDL3_NewFrame();
ImGui::NewFrame();

// ... Your draw code

Note that:

  • I am coding my project in C, not C++, so I tried my best to translate the relevant code but haven't tested it. The concept should be fairly clear anyway.
  • I believe it should work with other backends, as long as you can handle their scroll events yourself without ImGui seeing them.
@ocornut
Copy link
Owner

ocornut commented Feb 12, 2025

You calling UpdateInputEvents() before NewFrame() means it's going to be called 2 times every frame, which is incorrect and it going to cause problems.

The other problem is to test whether this would work with mouse/drivers that are already submitting smooth scrolling value as inputs.

Linking to #7348, #2675

@GloriousPtr
Copy link

With a quick test with my trackpad: scrolling works as expected but double tap (IsMouseDoubleClicked) stopped working

@Willy-JL
Copy link
Author

That makes a lot of sense actually, and aligns with what Omar mentioned. Then yeah what I proposed is definitely flawed in that state, I just never noticed as I don't have anything using double clicks in my apps using imgui.

I suppose the other approach of not passing the events to the imgui SDL3 backend and processing downstream before NewFrame() would work fine then, I will update the post.

Thank you both for the feedback!

@Willy-JL
Copy link
Author

Willy-JL commented Feb 13, 2025

Updated the snippet, no longer uses the internal UpdateInputEvents(), and also made it smooth horizontal scrolling. From what I can see double clicking should work fine now, I can double click the titlebar to collapse a ImGui window for example

@GloriousPtr
Copy link

Working quite well!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants
@ocornut @GloriousPtr @Willy-JL and others