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

Widgets only disabled when mouse over it #6373

Open
dimateos opened this issue Apr 26, 2023 · 4 comments
Open

Widgets only disabled when mouse over it #6373

dimateos opened this issue Apr 26, 2023 · 4 comments

Comments

@dimateos
Copy link
Contributor

Version/Branch of DearImGui:
Version: 1.89.2 WIP
Branch: docking

Back-end/Renderer/Compiler/OS
Back-ends: open source QT backend https://github.com/seanchas116/qtimgui
Operating System: Windows 10

Full config info
Dear ImGui 1.89.2 WIP (18916)
--------------------------------
sizeof(size_t): 8, sizeof(ImDrawIdx): 2, sizeof(ImDrawVert): 20
define: __cplusplus=199711
define: _WIN32
define: _WIN64
define: _MSC_VER=1916
define: _MSVC_LANG=201402
define: IMGUI_HAS_VIEWPORT
define: IMGUI_HAS_DOCK
--------------------------------
io.BackendPlatformName: qtimgui
io.BackendRendererName: NULL
io.ConfigFlags: 0x00000040
 DockingEnable
io.ConfigViewportsNoDecoration
io.ConfigInputTextCursorBlink
io.ConfigWindowsResizeFromEdges
io.ConfigMemoryCompactTimer = 60.0
io.BackendFlags: 0x00000006
 HasMouseCursors
 HasSetMousePos
--------------------------------
io.Fonts: 1 fonts, Flags: 0x00000000, TexSize: 512,64
io.DisplaySize: 1920.00,1082.00
io.DisplayFramebufferScale: 1.00,1.00
--------------------------------
style.WindowPadding: 8.00,8.00
style.WindowBorderSize: 1.00
style.FramePadding: 4.00,3.00
style.FrameRounding: 8.00
style.FrameBorderSize: 0.00
style.ItemSpacing: 8.00,4.00
style.ItemInnerSpacing: 4.00,4.00

My Issue/Question:

I was trying to cancel the user interaction with a slider whenever the value goes above a certain value. A quick hack I used was to disable the region for a frame the next frame. Probably there are better ways to do it with the API? Other option is to send a mouse up event from the backend I guess.

This worked fine but only whenever the cursor was over the widget on the disabled frame. A GIF for context:

viewer_plnbTi1mpH

Testing out a bit more I found that the user can keep interacting with disabled widgets in general as long as they are not touched. Just wanted to point it out as I did not find any comment about it.

Thanks for the lib!

Screenshots/Video

The region is disabled whenever the value is over 1.0 but the user can keep interacting as long as the disabled widget is not touched. Note that I did not used IsItemDeactivatedAfterEdit so the interaction is also canceled while manually inputting the value.

viewer_prABUepnzu

Standalone, minimal, complete and verifiable example: (see #2261)

if (ImGui::Begin("Test", nullptr)) {
    static float f = 0.5;
    static bool disabled = false;

    if (disabled) ImGui::BeginDisabled();
    //ImGui::BeginDisabled(disabled); // same

    ImGui::SliderFloat("f value", &f, 0, 2);
    if (disabled) ImGui::EndDisabled();

    disabled = f > 1;
    if (ImGui::Button("reset f")) f = 0.5;
}
ImGui::End();
@ocornut
Copy link
Owner

ocornut commented Apr 27, 2023

I was trying to cancel the user interaction with a slider whenever the value goes above a certain value.

That seems quite unusual. Why would you want to do that? Do you expect the interaction to brutally stop? How can the user resume operation once it is disabled?
Note that it won't magically lock the value to e.g. 1.0 but only the value during the frame the value exceeded (so it could be >1.0f).
What do you expect to happen?

You can use if (GetActiveID() == id) { ClearActiveID(); } to forcefully disable an action, but without more context the intent seems a little bizarre to me.

@dimateos
Copy link
Contributor Author

For context, it was the first idea I came up with to restrain the slider handle within a smaller range in relation to other sliders (the outer ranges shared for all of them). Later I linked the values instead of brutally stopping the interaction as you said. Not perfect as there is a frame delay when updating the values of sliders above. I thought or redrawing all to remove the latency but probably too complicated for a detail.

viewer_QS0jWHZM0G

Anyway, I brought up the fact that disabled widgets only stop interaction on mouse over for a more general discussion and documentation. I did not find a related issue, but now I found #3985 which seems related.

Why would you want to do that?

  • Maybe some condition in a game/app disables a section of the menu, would be weird to let the user keep interacting with draggable widgets when the mouse is away from them. In my case I think that stopping the interaction instead of linking the values is also an ok solution that could work with ClearActiveID() and setting the value to the expected limit.

Do you expect the interaction to brutally stop? How can the user resume operation once it is disabled?

  • Yes? basically the same as if the user had released the click, the same as what is happening when the disabled region is being touched. In an game/app some external condition would decide when to enable it again.

Note that it won't magically lock the value to e.g. 1.0 but only the value during the frame the value exceeded (so it could be >1.0f). What do you expect to happen?

  • Yep, the example was a demo. Binding the disabled state to the slider value was a way to ensure that the region got disabled while the widget was being interacted with, the exact value was not important. I would not expect imgui to restore the value like when the user exits an input field with ESC, which I guess works in an entirely different way.

Overall I think being able to keep dragging disabled widgets is quite an edge case and probably not worth it if it adds performance, and definitely would not prioritize it either.

Thanks your work! cheers

@ocornut
Copy link
Owner

ocornut commented Apr 28, 2023

For context, it was the first idea I came up with to restrain the slider handle within a smaller range in relation to other sliders (the outer ranges shared for all of them).

I suppose in theory we could add optional "clamping" values in SliderBehavior() that would be distinct from visible min/max range. However I believe the solution you found is much nicer for the end user.

Anyway, I brought up the fact that disabled widgets only stop interaction on mouse over

I agree this is something to address in theory, but being overwhelmed with tasks I would tend to avoid over-designing and solving edge cases like this if it doesn't address a concrete issue. So for now I would ignore it, and we may get back to it in the future when someone has a concrete problem. If clarifying/fixing that alone would fix your problem I would do it, but I don't think it is the right solution to your problem:

Do you expect the interaction to brutally stop? How can the user resume operation once it is disabled?
Yes? basically the same as if the user had released the click, the same as what is happening when the disabled region is being touched. In an game/app some external condition would decide when to enable it again.

And my question "How can the user resume operation once it is disabled?" is important and not fully answered here: if the intent it clamping, in your specific context you would surely want to allow the user to immediately click to move back in the opposite direction? Which the disabling solution wouldn't allow.

@dimateos
Copy link
Contributor Author

I suppose in theory we could add optional "clamping" values in SliderBehavior() that would be distinct from visible min/max range. However I believe the solution you found is much nicer for the end user.

That would be pretty nice for sliders that need to have the same context/scale but a different min/max. Should also fix the visual 1-frame latency I mentioned with the bottom slider moving the ones above. I would add an option to visually mark the real min/max within the range but that starts to sound like a custom widget. Probably similar to a range slider #76 but with a single value.

I agree this is something to address in theory, but being overwhelmed with tasks I would tend to avoid over-designing and solving edge cases like this if it doesn't address a concrete issue. So for now I would ignore it, and we may get back to it in the future when someone has a concrete problem.

I think you are doing great managing your tasks and I agree with ignoring it for now :) Indeed I don't disable other regions of the menu based on some app state at the momment. About the theoretical clamping in SliderBehavior() I also understand if you would leave it for the end user.

if the intent it clamping, in your specific context you would surely want to allow the user to immediately click to move back in the opposite direction? Which the disabling solution wouldn't allow.

Thats totally true, the underlaying intention is clamping and the user should be able to move it in the other direction. So the proposed internal clamping values would be the real solution: the handle would stop there but the user would keep interacting with the widget.

Feel free to rename the issue for more context or open a new one if you want to focus on the slider behavior, thanks a lot!

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

No branches or pull requests

2 participants