Fix 83efdcec from overflowing buffer + make it a single undo records + comments (#3008)
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index 9a60ef2..1970a63 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -76,7 +76,8 @@
those improvements in 1.73 makes them unnecessary. (#2722, #2770). [@rokups]
- ColorEdit: "Copy As" context-menu tool shows hex values with a '#' prefix instead of '0x'.
- ColorEdit: "Copy As" content-menu tool shows hex values both with/without alpha when available.
-- InputText: Fix crash when executing undo action after clearing input with ESC (#3008). [@rokups]
+- InputText: Fix corruption or crash when executing undo after clearing input with ESC, as a
+ byproduct we are allowing to later undo the revert with a CTRL+Z. (#3008).
- MenuBar: Fix minor clipping issue where occasionally a menu text can overlap the right-most border.
- Window: Fix SetNextWindowBgAlpha(1.0f) failing to override alpha component. (#3007) [@Albog]
- Window: When testing for the presence of the ImGuiWindowFlags_NoBringToFrontOnFocus flag we
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index 777530b..67bba18 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -3271,8 +3271,25 @@
#define STB_TEXTEDIT_IMPLEMENTATION
#include "imstb_textedit.h"
+// stb_textedit internally allows for a single undo record to do addition and deletion, but somehow, calling
+// the stb_textedit_paste() function creates two separate records, so we perform it manually. (FIXME: Report to nothings/stb?)
+static void stb_textedit_replace(STB_TEXTEDIT_STRING* str, STB_TexteditState* state, const STB_TEXTEDIT_CHARTYPE* text, int text_len)
+{
+ stb_text_makeundo_replace(str, state, 0, str->CurLenW, text_len);
+ ImStb::STB_TEXTEDIT_DELETECHARS(str, 0, str->CurLenW);
+ if (text_len <= 0)
+ return;
+ if (ImStb::STB_TEXTEDIT_INSERTCHARS(str, 0, text, text_len))
+ {
+ state->cursor = text_len;
+ state->has_preferred_x = 0;
+ return;
+ }
+ IM_ASSERT(0); // Failed to insert character, normally shouldn't happen because of how we currently use stb_textedit_replace()
}
+} // namespace ImStb
+
void ImGuiInputTextState::OnKeyPressed(int key)
{
stb_textedit_key(this, &Stb, key);
@@ -3826,27 +3843,16 @@
// Restore initial value. Only return true if restoring to the initial value changes the current buffer contents.
if (!is_readonly && strcmp(buf, state->InitialTextA.Data) != 0)
{
+ // Push records into the undo stack so we can CTRL+Z the revert operation itself
apply_new_text = state->InitialTextA.Data;
apply_new_text_length = state->InitialTextA.Size - 1;
-
- // Select all text
- state->OnKeyPressed(STB_TEXTEDIT_K_TEXTSTART);
- state->OnKeyPressed(STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT);
-
- // Paste converted text or empty buffer
- if (state->InitialTextA.size() > 1)
+ ImVector<ImWchar> w_text;
+ if (apply_new_text_length > 0)
{
- ImVector<ImWchar> w_text;
- const char* apply_new_text_end = apply_new_text + apply_new_text_length + 1;
- w_text.resize(ImTextCountCharsFromUtf8(apply_new_text, apply_new_text_end));
- ImTextStrFromUtf8(w_text.Data, w_text.Size, apply_new_text, apply_new_text_end);
- ImStb::stb_textedit_paste(state, &state->Stb, w_text.Data, w_text.Size);
+ w_text.resize(ImTextCountCharsFromUtf8(apply_new_text, apply_new_text + apply_new_text_length) + 1);
+ ImTextStrFromUtf8(w_text.Data, w_text.Size, apply_new_text, apply_new_text + apply_new_text_length);
}
- else
- {
- ImWchar empty = 0;
- ImStb::stb_textedit_paste(state, &state->Stb, &empty, 0);
- }
+ stb_textedit_replace(state, &state->Stb, w_text.Data, (apply_new_text_length > 0) ? (w_text.Size - 1) : 0);
}
}