ocornut / imgui

Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
MIT License
61.14k stars 10.3k forks source link

InputScalar()-based functions don't always respect EnterReturnsTrue #6284

Open rasmusbonnedal opened 1 year ago

rasmusbonnedal commented 1 year ago

Version/Branch of Dear ImGui:

Version: 1.89.4 Branch: v1.89.4

Back-end/Renderer/Compiler/OS

Back-ends: imgui_impl_glfw.cpp + imgui_impl_opengl3.cpp Compiler: VS2019 Operating System: Windows 11

My Issue/Question: I'm creating a form for inputting a lot of data so I'm trying to move keyboard focus to the next item when pressing enter in an input item. For this I use ImGuiInputTextFlags_EnterReturnsTrue. It works fine for InputText() but for InputScalar()-based functions it only returns true if pressing enter and the contents was changed.

I realize there is a caveat "Most of the ImGuiInputTextFlags flags are only useful for InputText()" in the code but since this almost works perfectly I thought it might be useful to bring it up. Sorry if it's not!

Screenshots/Video imgui_enter

Standalone, minimal, complete and verifiable example:

// Here's some code anyone can copy and paste to reproduce your issue
ImGui::Begin("Example Bug");
static int v = 0;
static bool int_enter = false;
if (ImGui::InputInt("int", &v, 0, 0, ImGuiInputTextFlags_EnterReturnsTrue)) {
    int_enter = true;
}
static bool text_enter = false;
static char buf[128] = "";
if (ImGui::InputText("text", buf, 127, ImGuiInputTextFlags_EnterReturnsTrue)) {
    text_enter = true;
}
if (int_enter) {
    ImGui::TextUnformatted("Enter was pressed in int input");
}
if (text_enter) {
    ImGui::TextUnformatted("Enter was pressed in text input");
}
ImGui::End();
rasmusbonnedal commented 1 year ago

inputscalar.patch I gave it a try to fix it.

rasmusbonnedal commented 1 year ago

If anyone else has a similar problem I was able to make a workaround using ImGui::IsItemDeactivatedAfterEdit() instead of ImGuiInputTextFlags_EnterReturnsTrue, like this:

ImGui::InputInt("int", &v, 0, 0);
if (ImGui::IsItemDeactivatedAfterEdit()) {
    int_enter = true;
}
ocornut commented 1 year ago

Please note IsItemDeactivatedAfterEdit() should trigger on tabbing out or clicking away, which is different than what ImGuiInputTextFlags_EnterReturnsTrue does.

I'll be looking at your patch, it seems like we could add that.

ocornut commented 1 year ago

For this and another feature, I was pondering adding a signal e.g. IsItemValidated() or IsItemDeactivatedAfterValidation() which would distinguish an explicit "Enter" validation from tabbing out.

However in general since there are only so many ways to validate a text field you could use:

if (IsItemDeactivatedAfterEdit() && (IsKeyPressed(ImGuiKey_Enter, false) || IsKeyPressed(ImGuiKey_KeypadEnter, false)))
{
    ...

I think it would be preferable you use this scheme until we decide if we need this status flag.

Technically speaking one can validate with a gamepad:

....
const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
const bool is_gamepad_validate = nav_gamepad_active && (IsKeyPressed(ImGuiKey_NavGamepadActivate, false) || IsKeyPressed(ImGuiKey_NavGamepadInput, false));
....

Which would be IMHO the main reason for adding an explicit signal.

rasmusbonnedal commented 1 year ago

Please note IsItemDeactivatedAfterEdit() should trigger on tabbing out or clicking away, which is different than what ImGuiInputTextFlags_EnterReturnsTrue does.

I meant to say it worked as workaround for me. It wasn't my intention to say they were equivalent. Thanks for the correction!

There is something else weird going on with InputScalar() and ImGuiInputTextFlags_EnterReturnsTrue. When I use it (this is without my patch, just ImGui 1.89.4) and press tab or click outside the widget, its content is reset to the original (as if ESC was pressed). This doesn't happen when not using ImGuiInputTextFlags_EnterReturnsTrue.

Here is a gif from my original code example, in the gif I write a value and then click the other input, then I write another value and press tab. imgui_click_tab