imgui icon indicating copy to clipboard operation
imgui copied to clipboard

Basic Smooth Scrolling Example

Open WillyJL opened this issue 10 months ago • 5 comments

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:

https://github.com/user-attachments/assets/a79a888f-c79a-4223-a561-31f657b288cc

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.

WillyJL avatar Feb 12 '25 04:02 WillyJL

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

ocornut avatar Feb 12 '25 09:02 ocornut

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

GloriousPtr avatar Feb 13 '25 02:02 GloriousPtr

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!

WillyJL avatar Feb 13 '25 02:02 WillyJL

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

WillyJL avatar Feb 13 '25 05:02 WillyJL

Working quite well!

GloriousPtr avatar Feb 13 '25 22:02 GloriousPtr