imgui icon indicating copy to clipboard operation
imgui copied to clipboard

Update InputFloat value with mouse wheel

Open masterleming opened this issue 4 years ago • 15 comments

Version/Branch of Dear ImGui:

Version: 1.83 Branch: docking

Back-end/Renderer/Compiler/OS

Back-ends: SDL2 + Vulkan Compiler: MSVC 16.9 Operating System: Windows 10

My Issue/Question:

I am trying to allow to increase or decrease InputFloat field value by scrolling mouse wheel while the field is hovered by mouse cursor. I managed to do so (see below for my provided example). However, when the window has vertical scrollbar my solution works only when the window scroll is at its limits, e.g. when the window is scrolled to the top, value in the hovered field can only be increased with the mouse wheel -- scrolling the mouse wheel down causes the window to scroll down and the value remains unchanged (note that when the widget is "active" it is deactivated at the first mouse wheel action, otherwise the value is changed only temporarily -- for one frame).

Could someone give me some pointers on how to proceed from here?

Screenshots/Video

mouse-wheel-4

Standalone, minimal, complete and verifiable example: (see https://github.com/ocornut/imgui/issues/2261)

bool InputFloatWithScroll( const char* label, float* v, const char* format, ImGuiInputTextFlags flags, float scrolStep )
{
    const bool rv = ImGui::InputFloat( label, v, 0.0f, 0.0f, format, flags );
    if( !ImGui::IsItemHovered() ) return rv;

    float wheel = ImGui::GetIO().MouseWheel;
    if ( wheel )
    {
        if( ImGui::IsItemActive() )
        {
            ImGui::ClearActiveID();
        }
        else
        {
            *v += wheel * scrolStep;
        }
    }
}

masterleming avatar Jun 07 '21 14:06 masterleming

Back-ends: SDL2 + Vulkan

Note that this is a completely custom backend implementation.

wolfpld avatar Jun 08 '21 09:06 wolfpld

Hello,

Not so long ago we formalized this with an imgui_internal.h function called SetItemUsingMouseWheel() (#2891):

ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
ImGui::SetItemUsingMouseWheel();
if (ImGui::IsItemHovered())
{
    float wheel = ImGui::GetIO().MouseWheel;
    if (wheel)
    {
        if (ImGui::IsItemActive())
        {
            ImGui::ClearActiveID();
        }
        else
        {
            f += wheel;
        }
    }
}

I would be interested in feedback and further example to figure out if this is a viable design to expose into the public API.

ocornut avatar Jun 08 '21 09:06 ocornut

Thanks! Somehow my previous attempt to use this function has failed. Not this time though!

Sticking with InputFloat I wrote this:

const bool rv = ImGui::InputFloat( label, v, 0.0f, 0.0f, format, flags );
ImGui::SetItemUsingMouseWheel();

if( !ImGui::IsItemHovered() ) return rv;

float wheel = ImGui::GetIO().MouseWheel;
if( wheel )
{
    if( ImGui::IsItemActive() )
    {
        ImGui::ClearActiveID();
    }
    else
    {
        *v += wheel * scrolStep;
    }
}
// [...]
return rv;

And it works just as expected -- prevents window from scrolling when the value is modified with mouse wheel. Once again, thank you for the assist!

masterleming avatar Jun 08 '21 10:06 masterleming

Good to hear! Technically speaking your *v += wheel * scrolStep; line should be followed by rv = true if you want to notify caller of a value change.

Closing this.

ocornut avatar Jun 09 '21 13:06 ocornut

I would be interested in feedback and further example to figure out if this is a viable design to expose into the public API.

So far, this is working well in my use cases. I ended up wrapping the widgets that I want to interact with the mouse wheel up in custom functions, and am using ImGui::SetItemUsingMouseWheel.

Working great so far. Would vote to have this exposed in the public API. 👍

michaelquigley avatar Oct 21 '21 15:10 michaelquigley

I just upgraded my codebase to v1.89.1, and I'm getting errors now trying to use SetItemUsingMouseWheel.

I see this in imgui_internal.h:

    // Obsolete functions
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
    inline void     SetItemUsingMouseWheel()                                            { SetItemKeyOwner(ImGuiKey_MouseWheelY); }      // Changed in 1.89

But I'm not really finding any details on what the current mechanism is to support this functionality?

michaelquigley avatar Nov 28 '22 20:11 michaelquigley

Err, you literally pasted the answer to your question? Use SetItemKeyOwner().

ocornut avatar Nov 28 '22 20:11 ocornut

I get that. Is this functionality stable, even if the naming keeps changing?

michaelquigley avatar Nov 28 '22 22:11 michaelquigley

Everything in imgui_internal.h is technically not guaranteed to be stable, but SetItemKeyOwner() is the way forward. As SetItemUsingMouseWheel() was mentioned in #5108 #4303 #4207 #2891 #2704 I added a redirection function in imgui_internal.h but those are fairly exceptional and the SetItemUsingMouseWheel() inline function will eventually be removed.

ocornut avatar Nov 29 '22 11:11 ocornut

@ocornut sorry for bugging you for a century old and closed issue. Is there any chance of making SetItemKeyOwner() a public API function rather than internal API.

Basically I am trying to do what this issue is talking about but in C#. :)

zaafar avatar Dec 21 '22 02:12 zaafar

It will be progressively be made public when the API has been used enough.

I think you should ask for your C# bindings to allow access to imgui_internal too.

ocornut avatar Dec 21 '22 05:12 ocornut

Hi, Is there any new solution to this that allows scrolling of the region that contains the slider to not stop when the mouse just so happens to land on a slider? Afaik most UI systems handle this by checking of the mouse has moved or not following the scrolling of the container but I'm not sure how to cleanly implement this.

AlexandreRouma avatar Feb 13 '23 12:02 AlexandreRouma

Should probably check that the mouse moving window lock is disabled before claiming ownership. Will try to test this.

ocornut avatar Feb 13 '23 13:02 ocornut

Hi again, Any update on this? Even if not in ImGui, a working way to do this as a custom widget would be helpful :+1:

AlexandreRouma avatar May 12 '23 12:05 AlexandreRouma

Here's an incomplete wrapper I created to support this usecase: https://gist.github.com/Folling/06c223badea6fb7da76d8039947f2398. This almost certainly misses certain ergonomics like focus handling, keyboard navigation, styling, etc. I didn't do a full test, so it should be seen as a jumping off point for proper applications — works for our internal tool though. The label rendering is a bit hacky, I didn't find any better way without using imgui_internal.

As for Dear ImGui itself, it would be nice to have a new ImGuiSliderFlag to support scrolling ootb. I can create a PR for this if desired.

Folling avatar Nov 16 '25 12:11 Folling