Skip to content

Commit f9f4e22

Browse files
committed
InputText: some tidying up. (#7925)
1 parent 4cc464e commit f9f4e22

File tree

2 files changed

+21
-33
lines changed

2 files changed

+21
-33
lines changed

imgui_internal.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,7 @@ struct IMGUI_API ImGuiInputTextState
11211121
{
11221122
ImGuiContext* Ctx; // parent UI context (needs to be set explicitly by parent).
11231123
ImStbTexteditState* Stb; // State for stb_textedit.h
1124+
ImGuiInputTextFlags Flags; // copy of InputText() flags. may be used to check if e.g. ImGuiInputTextFlags_Password is set.
11241125
ImGuiID ID; // widget id owning the text state
11251126
int TextLen; // UTF-8 length of the string in TextA (in bytes)
11261127
ImVector<char> TextA; // main UTF8 buffer. TextA.Size is a buffer size! Should always be >= buf_size passed by user (and of course >= CurLenA + 1).
@@ -1132,9 +1133,8 @@ struct IMGUI_API ImGuiInputTextState
11321133
bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!)
11331134
bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection
11341135
bool Edited; // edited this frame
1135-
ImGuiInputTextFlags Flags; // copy of InputText() flags. may be used to check if e.g. ImGuiInputTextFlags_Password is set.
11361136
bool ReloadUserBuf; // force a reload of user buf so it may be modified externally. may be automatic in future version.
1137-
int ReloadSelectionStart; // POSITIONS ARE IN IMWCHAR units *NOT* UTF-8 this is why this is not exposed yet.
1137+
int ReloadSelectionStart;
11381138
int ReloadSelectionEnd;
11391139

11401140
ImGuiInputTextState();
@@ -1159,6 +1159,7 @@ struct IMGUI_API ImGuiInputTextState
11591159
// strcpy(my_buf, "hello");
11601160
// if (ImGuiInputTextState* state = ImGui::GetInputTextState(id)) // id may be ImGui::GetItemID() is last item
11611161
// state->ReloadUserBufAndSelectAll();
1162+
// THIS CURRENTLY RESETS THE UNDO STACK.
11621163
void ReloadUserBufAndSelectAll();
11631164
void ReloadUserBufAndKeepSelection();
11641165
void ReloadUserBufAndMoveToEnd();

imgui_widgets.cpp

+18-31
Original file line numberDiff line numberDiff line change
@@ -4041,16 +4041,12 @@ static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx)
40414041

40424042
static void STB_TEXTEDIT_DELETECHARS(ImGuiInputTextState* obj, int pos, int n)
40434043
{
4044+
// Offset remaining text (+ copy zero terminator)
40444045
char* dst = obj->TextA.Data + pos;
4045-
4046+
char* src = obj->TextA.Data + pos + n;
4047+
memmove(dst, src, obj->TextLen - n - pos + 1);
40464048
obj->Edited = true;
40474049
obj->TextLen -= n;
4048-
4049-
// Offset remaining text (FIXME-OPT: Use memmove)
4050-
const char* src = obj->TextA.Data + pos + n;
4051-
while (char c = *src++)
4052-
*dst++ = c;
4053-
*dst = '\0';
40544050
}
40554051

40564052
static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const char* new_text, int new_text_len)
@@ -4174,17 +4170,16 @@ ImGuiInputTextCallbackData::ImGuiInputTextCallbackData()
41744170
memset(this, 0, sizeof(*this));
41754171
}
41764172

4177-
// Public API to manipulate UTF-8 text
4178-
// We expose UTF-8 to the user (unlike the STB_TEXTEDIT_* functions which are manipulating wchar)
4173+
// Public API to manipulate UTF-8 text from within a callback.
41794174
// FIXME: The existence of this rarely exercised code path is a bit of a nuisance.
4175+
// Historically they existed because STB_TEXTEDIT_INSERTCHARS() etc. worked on our ImWchar
4176+
// buffer, but nowadays they both work on UTF-8 data. Should aim to merge both.
41804177
void ImGuiInputTextCallbackData::DeleteChars(int pos, int bytes_count)
41814178
{
41824179
IM_ASSERT(pos + bytes_count <= BufTextLen);
41834180
char* dst = Buf + pos;
41844181
const char* src = Buf + pos + bytes_count;
4185-
while (char c = *src++)
4186-
*dst++ = c;
4187-
*dst = '\0';
4182+
memmove(dst, src, BufTextLen - bytes_count - pos + 1);
41884183

41894184
if (CursorPos >= pos + bytes_count)
41904185
CursorPos -= bytes_count;
@@ -4209,7 +4204,6 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons
42094204
if (!is_resizable)
42104205
return;
42114206

4212-
// Contrary to STB_TEXTEDIT_INSERTCHARS() this is working in the UTF8 buffer, hence the mildly similar code (until we remove the U16 buffer altogether!)
42134207
ImGuiContext& g = *Ctx;
42144208
ImGuiInputTextState* edit_state = &g.InputTextState;
42154209
IM_ASSERT(edit_state->ID != 0 && g.ActiveId == edit_state->ID);
@@ -4333,26 +4327,23 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, Im
43334327
return true;
43344328
}
43354329

4336-
// Find the shortest single replacement we can make to get the new text from the old text.
4337-
// Important: needs to be run before TextW is rewritten with the new characters because calling STB_TEXTEDIT_GETCHAR() at the end.
4330+
// Find the shortest single replacement we can make to get from old_buf to new_buf
4331+
// Note that this doesn't directly alter state->TextA, state->TextLen. They are expected to be made valid separately.
43384332
// FIXME: Ideally we should transition toward (1) making InsertChars()/DeleteChars() update undo-stack (2) discourage (and keep reconcile) or obsolete (and remove reconcile) accessing buffer directly.
4339-
static void InputTextReconcileUndoStateAfterUserCallback(ImGuiInputTextState* state, const char* new_buf_a, int new_length_a)
4333+
static void InputTextReconcileUndoState(ImGuiInputTextState* state, const char* old_buf, int old_length, const char* new_buf, int new_length)
43404334
{
4341-
const char* old_buf = state->CallbackTextBackup.Data;
4342-
const int old_length = state->CallbackTextBackup.Size - 1;
4343-
4344-
const int shorter_length = ImMin(old_length, new_length_a);
4335+
const int shorter_length = ImMin(old_length, new_length);
43454336
int first_diff;
43464337
for (first_diff = 0; first_diff < shorter_length; first_diff++)
4347-
if (old_buf[first_diff] != new_buf_a[first_diff])
4338+
if (old_buf[first_diff] != new_buf[first_diff])
43484339
break;
4349-
if (first_diff == old_length && first_diff == new_length_a)
4340+
if (first_diff == old_length && first_diff == new_length)
43504341
return;
43514342

43524343
int old_last_diff = old_length - 1;
4353-
int new_last_diff = new_length_a - 1;
4344+
int new_last_diff = new_length - 1;
43544345
for (; old_last_diff >= first_diff && new_last_diff >= first_diff; old_last_diff--, new_last_diff--)
4355-
if (old_buf[old_last_diff] != new_buf_a[new_last_diff])
4346+
if (old_buf[old_last_diff] != new_buf[new_last_diff])
43564347
break;
43574348

43584349
const int insert_len = new_last_diff - first_diff + 1;
@@ -4544,16 +4535,12 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
45444535
if (flags & ImGuiInputTextFlags_ElideLeft)
45454536
state->Scroll.x += ImMax(0.0f, CalcTextSize(buf).x - frame_size.x + style.FramePadding.x * 2.0f);
45464537

4538+
// Recycle existing cursor/selection/undo stack but clamp position
4539+
// Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler.
45474540
if (recycle_state)
4548-
{
4549-
// Recycle existing cursor/selection/undo stack but clamp position
4550-
// Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler.
45514541
state->CursorClamp();
4552-
}
45534542
else
4554-
{
45554543
stb_textedit_initialize_state(state->Stb, !is_multiline);
4556-
}
45574544

45584545
if (init_reload_from_user_buf)
45594546
{
@@ -5039,7 +5026,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
50395026
{
50405027
// Callback may update buffer and thus set buf_dirty even in read-only mode.
50415028
IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
5042-
InputTextReconcileUndoStateAfterUserCallback(state, callback_data.Buf, callback_data.BufTextLen); // FIXME: Move the rest of this block inside function and rename to InputTextReconcileStateAfterUserCallback() ?
5029+
InputTextReconcileUndoState(state, state->CallbackTextBackup.Data, state->CallbackTextBackup.Size - 1, callback_data.Buf, callback_data.BufTextLen);
50435030
state->TextLen = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen()
50445031
state->CursorAnimReset();
50455032
}

0 commit comments

Comments
 (0)