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

InputText, InputInt, InputFloat: add ImGuiInputTextFlags_NoLiveEdit flag #701

Open
ocornut opened this issue Jun 16, 2016 · 13 comments
Open

Comments

@ocornut
Copy link
Owner

ocornut commented Jun 16, 2016

ImGuiInputTextFlags_NoLiveEdit (tentative name) would only apply the value when pressing Return or intentionally changing focus via Tab, as opposed to the current behaviour of applying the value as it is being edited. How about when unintentionally losing focus?

(ref. #700)

@Cthutu
Copy link

Cthutu commented Jun 16, 2016

That's ok. That's how windows and OS X handles it
On Thu, Jun 16, 2016 at 16:14, omar notifications@github.com wrote:

ImGuiInputTextFlags_NoLiveEdit (tentative name) would only apply the
value when pressing Return or intentionally changing focus via Tab, as
opposed to the current behaviour of applying the value as it is being
edited. How about when unintentionally losing focus?

(ref. #700 #700)


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
#701, or mute the thread
https://github.com/notifications/unsubscribe/AAVRxqolsk47I99TmR3Z1JuP55sWPUtkks5qMa6qgaJpZM4I3w-k
.

@ocornut
Copy link
Owner Author

ocornut commented Jun 16, 2016

Setting the xyz values of an object is something you don't live update on,
otherwise the object will be jumping about as you type :)

I think live update makes more sense for string/text values than for float/int.
I am considering changing the default so that for float/int it wouldn't live update by default. Will poll people on twitter for that.

@ocornut
Copy link
Owner Author

ocornut commented Jun 17, 2016

FYI started working on this but it is hard to accomplish 100% in an imgui context.
We can only write back within the InputXXX call so it means the function needs to tell that it is being stolen focus. While it is feasible to cover the most common case (such as tabbing, or explicitly clicking outside) some other cases are harder (any code explicitly stealing ActiveId would be a problem, or user stopping to render the widget/window would allow lose the data but that is less of a problem). Looking into it.

@Cthutu
Copy link

Cthutu commented Jun 17, 2016

I don't think you should have different defaults depending on the type of values (string or float etc). I think it should be consistent in the API. Maybe make live editing not the default and add a ImGuiTextEditFlags_LiveEdit?

@ocornut
Copy link
Owner Author

ocornut commented Jun 25, 2016

Putting this on hold until I do a big cleanup to add UTF-8 to stb_textedit and ditch the back and forth conversions. The code before the is too risky and bug-prone.

Basically we need to store the data so that when another text widget submitted earlier steals focus and starts editing, the old data is still available for the next recently-been-editing widget to apply back to the user variable. So that means likely we'll need to have two text buffers in memory and alternate their use to avoid extra copying of data. Currently InputText() is too complex because of how it has to work-around limitation of stb_textedit while staying efficient for large text, so I am going to fix that first (not a big big change).

ocornut added a commit that referenced this issue Jul 19, 2016
…stly a workaround to that activation with enter doesn't validate immediately, which is turns triggers an assert in InputScalarAsWidgetReplacement - can't see an issue with changing it this way so trying out) + using local flag clear_active_id to only clear the active id at the end of the frame, which is one of the step that my stash for #701 requires. (#323)
ocornut added a commit that referenced this issue Aug 13, 2016
@drudru
Copy link

drudru commented Jul 17, 2018

👍
Ran into this as well for a property editor. I was able to work around it.
However, wanted to chime so I can stay up to date on this topic.

@damqui
Copy link

damqui commented Jul 31, 2018

same here also for a property editor. what was your work around ? using intermediate buffer with live edit + copying into edited value when focus lost / tab / enter ?

@franciscod
Copy link
Contributor

Is #2034 / the new IsItemEdited() relevant here?

@ocornut
Copy link
Owner Author

ocornut commented Sep 3, 2018

It is relevant as being useful but it doesn't technically solve this issue #701 as the value is still always written back to the user's buffer at the moment.

@sergeiromanov
Copy link

+1 Having the same problem. Would be nice to achieve "normal" behavior without workarounds. Live updates are problem for property editors

@hls333555
Copy link

Any update on this?

@mnesarco
Copy link

Hello, I have the same problem with my own property editor. Any update on this? or is there any known workaround to disable Live edit?

@alektron
Copy link
Contributor

alektron commented Apr 4, 2024

I recently needed this feature as well, mainly due to the usual undo/redo shenanigans where I would like to only get the updated value on enter/focus lost etc. and not edit the actual string (yet).
I wasn't quite happy with the solution of preemptively copying the string into e.g. a static variable before passing it in, so I did a little digging and implemented my own little hacky NoLiveEdit flag.

Now I am well aware that implementing this feature properly while keeping edge cases, backwards compatibility etc. in mind is a huge task and I do not want to imply that my hacky solution does that AT ALL.
However it required such a tiny little change that I would like to discuss is anyways. On one hand, who knows, maybe it is actually a good idea that might help with implementing the proper solution. On the other hand, if there are obvious flaws that I could not find, knowing about those would be good as well (mostly for my own benefit, I guess).

What I did is the following:
In the imgui source, the only change I had to do was, of course, add the NoLiveEdit flag and if it was set, block all text changes from being written back to user buffer like so (imgui_widgets.cpp)

// Copy result to user buffer. This can currently only happen when (g.ActiveId == id)
if (apply_new_text != NULL && (flags & ImGuiInputTextFlags_NoLiveEdit) == 0)
{
 //...
}

(Technically there is at least one other place, that could be skipped. Where the internal buffer is compared to the user buffer to detect if any changes have been made. However I didn't bother for now).
While editing the InputText we now exclusively work on the internal copy. As far as I can tell, this does not impact the behaviour of the widget at all, except for the fact that the resize callback will never be called which is what we want anyways.

Now we somehow have to access the changes, once the editing is actually finished.
To accomplish that I make use of the (afaik already undesired) TextDeactivateHook feature that was added, so the internal text buffer can still be accessed after the InputText became inactive, like so

ImGui::InputText("Name", &model->Name, ImGuiInputTextFlags_NoLiveEdit);
if (ImGui::IsItemDeactivatedAfterEdit()) {
  auto& state = ImGui::GetCurrentContext()->InputTextDeactivatedState;

  //Do something with 'state.TextA.Data'/'state.TextA.Size'
}

In my case I neatly hid that admittedly undesired context access into a little wrapper function

std::string_view GetLastDeactivatedText()
{
  auto& state = ImGui::GetCurrentContext()->InputTextDeactivatedState;
  return std::string_view(state.TextA.Data, state.TextA.Size);
}

This almost works already, with the exception of pressing 'Esc' which should discard the changes. Currently 'Esc' still triggers the IsItemDeactivatedAfterEdit(). We can easily bypass this by making use of the fact that InputText returns true on pretty much all actions except 'Esc'. That is, pressing Enter, Tab, or clicking somewhere outside the widget (including into other widgets) all return true, while pressing 'Esc' returns false.
We can then do this:

bool update = ImGui::InputText("Name", &model->Name, ImGuiInputTextFlags_NoLiveEdit);
if (ImGui::IsItemDeactivatedAfterEdit() && update) {
  auto& state = ImGui::GetCurrentContext()->InputTextDeactivatedState;

  //Do something with 'state.TextA.Data'/'state.TextA.Size'
}

And that's about it. While it is a little more work in user code than just adding the flag, the code "overhead" of the IsItemDeactivatedAfterEdit seems acceptable to me. I'm not entirely sure about accessing InputTextDeactivatedState directy. That may or may not be a bad idea.
Like I said, I do not necessarily expect this to be the one big great solution. It is quite impossible for me to judge the impact this has on the overarching code base and existing user code. I know there are also other open issue that are, in some way or another, related to this feature. However the only issue I encountered so far is a one-frame flicker when tabbing out of the widget. That being said, I didn't really check the usage of most other flags/flag-combinations. Just wanted to get it out there in case it helps, since it was such a little change.

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

9 participants