InputText: cleanup/rework old comments + remove unnecessary indent in callback and main block setting apply_new_text.

Amend 00f12b9a0, 3349296370 etc.
This commit is contained in:
ocornut
2026-03-16 18:42:28 +01:00
parent 16772365e2
commit 6464276b62
2 changed files with 90 additions and 98 deletions
+1
View File
@@ -1258,6 +1258,7 @@ struct IMGUI_API ImGuiInputTextState
void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation
void OnCharPressed(unsigned int c); void OnCharPressed(unsigned int c);
float GetPreferredOffsetX() const; float GetPreferredOffsetX() const;
const char* GetText() { return TextA.Data ? TextA.Data : ""; }
// Cursor & Selection // Cursor & Selection
void CursorAnimReset(); void CursorAnimReset();
+10 -19
View File
@@ -5217,7 +5217,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
render_selection |= state->HasSelection() && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor); render_selection |= state->HasSelection() && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor);
} }
// Process callbacks and apply result back to user's buffer. // Process revert and user callbacks
const char* apply_new_text = NULL; const char* apply_new_text = NULL;
int apply_new_text_length = 0; int apply_new_text_length = 0;
if (g.ActiveId == id) if (g.ActiveId == id)
@@ -5247,18 +5247,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
} }
} }
// FIXME-OPT: We always reapply the live buffer back to the input buffer before clearing ActiveId,
// even though strictly speaking it wasn't modified on this frame. Should mark dirty state from the stb_textedit callbacks.
// If we do that, need to ensure that as special case, 'validated == true' also writes back.
// This also allows the user to use InputText() without maintaining any user-side storage.
// (please note that if you use this property along ImGuiInputTextFlags_CallbackResize you can end up with your temporary string object
// unnecessarily allocating once a frame, either store your string data, either if you don't then don't use ImGuiInputTextFlags_CallbackResize).
const bool apply_edit_back_to_user_buffer = true;// !revert_edit || (validated && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0);
if (apply_edit_back_to_user_buffer)
{
// Apply current edited text immediately.
// Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer
// User callback // User callback
if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackAlways)) != 0) if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackAlways)) != 0)
{ {
@@ -5340,7 +5328,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
} }
} }
// Will copy result string if modified // Will copy result string if modified.
// FIXME-OPT: Could mark dirty state from the stb_textedit callbacks
if (!is_readonly && strcmp(state->TextSrc, buf) != 0) if (!is_readonly && strcmp(state->TextSrc, buf) != 0)
{ {
apply_new_text = state->TextSrc; apply_new_text = state->TextSrc;
@@ -5348,9 +5337,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
value_changed = true; value_changed = true;
} }
} }
}
// Handle reapplying final data on deactivation (see InputTextDeactivateHook() for details) // Handle reapplying final data on deactivation (see InputTextDeactivateHook() for details)
// This is used when e.g. losing focus or tabbing out into another InputText() which may already be using the temp buffer.
if (g.InputTextDeactivatedState.ID == id) if (g.InputTextDeactivatedState.ID == id)
{ {
if (g.ActiveId != id && IsItemDeactivatedAfterEdit() && !is_readonly && strcmp(g.InputTextDeactivatedState.TextA.Data, buf) != 0) if (g.ActiveId != id && IsItemDeactivatedAfterEdit() && !is_readonly && strcmp(g.InputTextDeactivatedState.TextA.Data, buf) != 0)
@@ -5363,12 +5352,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
g.InputTextDeactivatedState.ID = 0; g.InputTextDeactivatedState.ID = 0;
} }
// Copy result to user buffer. This can currently only happen when (g.ActiveId == id) // Write back result to user buffer. This can currently only happen when (g.ActiveId == id) or when just deactivated.
// - As soon as the InputText() is active, our stored in-widget value gets priority over any underlying modification of the user buffer.
// - Make sure we always reapply the live buffer back to the input/user buffer before clearing ActiveId, even thought strictly speaking
// it was not modified on this frame. This allows the user to use InputText() without maintaining any user-side storage.
// (PS: if you use this property together with ImGuiInputTextFlags_CallbackResize, you are at the risk of recreating a temporary
// allocated/string object every frame. Which in the grand scheme of scheme is nothing, but isn't dear imgui vibe).
if (apply_new_text != NULL) if (apply_new_text != NULL)
{ {
//// We cannot test for 'backup_current_text_length != apply_new_text_length' here because we have no guarantee that the size
//// of our owned buffer matches the size of the string object held by the user, and by design we allow InputText() to be used
//// without any storage on user's side.
IM_ASSERT(apply_new_text_length >= 0); IM_ASSERT(apply_new_text_length >= 0);
if (is_resizable) if (is_resizable)
{ {