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

Return true on enter or when item was deactivated #3083

Closed
mphe opened this issue Mar 29, 2020 · 2 comments
Closed

Return true on enter or when item was deactivated #3083

mphe opened this issue Mar 29, 2020 · 2 comments

Comments

@mphe
Copy link

mphe commented Mar 29, 2020

Version/Branch of Dear ImGui:

Version: 1d4b5de
Branch: master

My Issue/Question:
This is half question, half feature request. I'm looking for a way to make widgets only return true when either enter was pressed or the widget was deactivated, e.g. by clicking somewhere else or pressing tab.

The reason is that I want to apply the new value only when the user has finished typing.
For example, using the following code, if the user enters 123, x will be consecutively assigned 1, 12, 123, which is not always desirable, especially if the effect of this variable has high computational impact or other consequences.

int x;
ImGui::InputInt("x", &x)

To prevent this, I'm currently using ImGuiInputTextFlags_EnterReturnsTrue in combination with a temporary copy of the actual value.

int realint = 42; // defined somewhere in the code

// in every frame run...
int tmpint = realint;
if (ImGui::InputInt("int", &tmpint, 1, 100, ImGuiInputTextFlags_EnterReturnsTrue))
    realint = tmpint;

This prevents the actual variable from changing before the user has finished typing.
However, it obviously only works when the user presses enter, otherwise the value gets reset.
Unfortunetly this is a bit counter intuitive, as you often want to press tab to jump to the next field, but this will also reset the current field.

This is why I'm searching for a way to let widgets also return true when they were deactivated.
I can't just check IsItemDeactivated() afterwards and then set the value, because

  • the temporary variable is not static and therefore doesn't store the changes made previously
  • accessing the widget buffer using GImGui->InputTextState is unreliable.

I tried to access the widget buffer in the following way.

void printbuffer(const char* label)
{
    if (!ImGui::IsItemDeactivated())
        return;

    const ImGuiID id = ImGui::GetCurrentWindow()->GetID(label);
    const ImGuiInputTextState& state = GImGui->InputTextState;
    if (state.ID == id)
        std::cout << "bufferA: " << state.TextA.Data << std::endl;
}

std::string realtext = "foobar";
int realint = 0;

int tmpint = realint;
if (ImGui::InputInt("int", &tmpint, 1, 100, ImGuiInputTextFlags_EnterReturnsTrue))
{
    realint = tmpint;
    std::cout << "accepted: " << tmpint << std::endl;
}
printbuffer("int");

std::string tmptext = realtext;
if (ImGui::InputText("text", &tmptext, ImGuiInputTextFlags_EnterReturnsTrue))
{
    realtext = tmptext;
    std::cout << "accepted: " << tmptext << std::endl;
}
printbuffer("text");

This seemed to work fine so far, except when tabbing away from the last widget, back to the first. In that case (and maybe there are other edge cases, too, that I haven't noticed yet), the ID check fails and the buffer already contains the data of the next widget.
Also even if this would work consistently, I would still need to manually convert the string back to the actual datatype, which would result in quite some extra work.

Is there any other way to accomplish this behavior?

Ideally there would be a new flag that works like EnterReturnsTrue, except it checks for deactivation, so you can write it like this:

InputText("text", &text, ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_DeactivateReturnsTrue)
@ocornut
Copy link
Owner

ocornut commented Apr 2, 2020

Hello,

That hypothetical ImGuiInputTextFlags_DeactivateReturnsTrue flag would likely get into the same problem that you are already getting into.

This essentially the same as described in #701, I don't think there is a out-of-the-box solution yet.
My guess is your best bet would be to work-around that llimitation:

the temporary variable is not static and therefore doesn't store the changes made previously

By allocating some storage, which may be as simple storing 1 value + 1 id (and maybe that can become more elaborate or cache 2 last value+ID If needed).

So you'd create a wrapper, MyInputInt() which calls GetID() + InputInt() + IsItemDeactivatedAfterEdit() and sync them in one or the other direction based on the current active id.

@mphe
Copy link
Author

mphe commented Apr 8, 2020

Thanks, I see now why this is not so trivial to implement.

I'll try your suggestion and post my solution here, when I found one, in case someone else stumbles over the same problem.

I guess this can be closed, since it's the same as #701.

@mphe mphe closed this as completed Apr 8, 2020
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

2 participants