mirror of
https://github.com/Drezil/imgui.git
synced 2024-11-26 05:27:01 +00:00
InputText: callback InsertChars() support resize callbacks correctly (followup to 24ff259
) + fixed demo to use those functions. (#2006, #1443, #1008).
This commit is contained in:
parent
ea1906004b
commit
8d639ec60d
@ -86,6 +86,8 @@ Other Changes:
|
|||||||
- Metrics: Added io.MetricsRenderWindow to reflect the number of visible windows.
|
- Metrics: Added io.MetricsRenderWindow to reflect the number of visible windows.
|
||||||
- Metrics: Added io.MetricsActiveAllocations, moving away from the cross-context global counters than we previously used. (#1565, #1599, #586)
|
- Metrics: Added io.MetricsActiveAllocations, moving away from the cross-context global counters than we previously used. (#1565, #1599, #586)
|
||||||
- Demo: Added basic Drag and Drop demo. (#143)
|
- Demo: Added basic Drag and Drop demo. (#143)
|
||||||
|
- Demo: Modified the Console example to use InsertChars() in the input text callback instead of poking directly into the buffer.
|
||||||
|
Although this won't make a difference in the example itself, using InsertChars() will honor the resizing callback properly. (#2006, #1443, #1008).
|
||||||
- Demo: Clarified the use of IsItemHovered()/IsItemActive() right after being in the "Active, Focused, Hovered & Focused Tests" section.
|
- Demo: Clarified the use of IsItemHovered()/IsItemActive() right after being in the "Active, Focused, Hovered & Focused Tests" section.
|
||||||
- Examples: Tweaked the main.cpp of each example.
|
- Examples: Tweaked the main.cpp of each example.
|
||||||
- Examples: Metal: Added Metal rendering backend. (#1929, #1873) [@warrenm]
|
- Examples: Metal: Added Metal rendering backend. (#1929, #1873) [@warrenm]
|
||||||
|
29
imgui.cpp
29
imgui.cpp
@ -10622,9 +10622,23 @@ void ImGuiInputTextCallbackData::DeleteChars(int pos, int bytes_count)
|
|||||||
|
|
||||||
void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, const char* new_text_end)
|
void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, const char* new_text_end)
|
||||||
{
|
{
|
||||||
|
const bool is_resizable = (Flags & ImGuiInputTextFlags_CallbackResize) != 0;
|
||||||
const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text);
|
const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text);
|
||||||
if (new_text_len + BufTextLen + 1 >= BufSize)
|
if (new_text_len + BufTextLen >= BufSize)
|
||||||
return;
|
{
|
||||||
|
if (!is_resizable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Contrary to STB_TEXTEDIT_INSERTCHARS() this is working in the UTF8 buffer, hence the midly similar code (until we remove the U16 buffer alltogether!)
|
||||||
|
ImGuiContext& g = *GImGui;
|
||||||
|
ImGuiInputTextState* edit_state = &g.InputTextState;
|
||||||
|
IM_ASSERT(edit_state->ID != 0 && g.ActiveId == edit_state->ID);
|
||||||
|
IM_ASSERT(Buf == edit_state->TempBuffer.Data);
|
||||||
|
int new_buf_size = BufTextLen + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1;
|
||||||
|
edit_state->TempBuffer.reserve(new_buf_size + 1);
|
||||||
|
Buf = edit_state->TempBuffer.Data;
|
||||||
|
BufSize = edit_state->BufCapacityA = new_buf_size;
|
||||||
|
}
|
||||||
|
|
||||||
if (BufTextLen != pos)
|
if (BufTextLen != pos)
|
||||||
memmove(Buf + pos + new_text_len, Buf + pos, (size_t)(BufTextLen - pos));
|
memmove(Buf + pos + new_text_len, Buf + pos, (size_t)(BufTextLen - pos));
|
||||||
@ -10710,8 +10724,6 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|||||||
|
|
||||||
IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys)
|
IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys)
|
||||||
IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key)
|
IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key)
|
||||||
if (flags & ImGuiInputTextFlags_CallbackResize)
|
|
||||||
IM_ASSERT(callback != NULL);
|
|
||||||
|
|
||||||
ImGuiContext& g = *GImGui;
|
ImGuiContext& g = *GImGui;
|
||||||
const ImGuiIO& io = g.IO;
|
const ImGuiIO& io = g.IO;
|
||||||
@ -10721,6 +10733,9 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|||||||
const bool is_editable = (flags & ImGuiInputTextFlags_ReadOnly) == 0;
|
const bool is_editable = (flags & ImGuiInputTextFlags_ReadOnly) == 0;
|
||||||
const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0;
|
const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0;
|
||||||
const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0;
|
const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0;
|
||||||
|
const bool is_resizable = (flags & ImGuiInputTextFlags_CallbackResize) != 0;
|
||||||
|
if (is_resizable)
|
||||||
|
IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag!
|
||||||
|
|
||||||
if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope,
|
if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope,
|
||||||
BeginGroup();
|
BeginGroup();
|
||||||
@ -11056,7 +11071,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|||||||
// FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks.
|
// FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks.
|
||||||
if (is_editable)
|
if (is_editable)
|
||||||
{
|
{
|
||||||
edit_state.TempBuffer.resize(edit_state.TextW.Size * 4);
|
edit_state.TempBuffer.resize(edit_state.TextW.Size * 4 + 1);
|
||||||
ImTextStrToUtf8(edit_state.TempBuffer.Data, edit_state.TempBuffer.Size, edit_state.TextW.Data, NULL);
|
ImTextStrToUtf8(edit_state.TempBuffer.Data, edit_state.TempBuffer.Size, edit_state.TextW.Data, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11119,6 +11134,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|||||||
if (callback_data.BufDirty)
|
if (callback_data.BufDirty)
|
||||||
{
|
{
|
||||||
IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
|
IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
|
||||||
|
if (callback_data.BufTextLen > backup_current_text_length && is_resizable)
|
||||||
|
edit_state.TextW.resize(edit_state.TextW.Size + (callback_data.BufTextLen - backup_current_text_length));
|
||||||
edit_state.CurLenW = ImTextStrFromUtf8(edit_state.TextW.Data, edit_state.TextW.Size, callback_data.Buf, NULL);
|
edit_state.CurLenW = ImTextStrFromUtf8(edit_state.TextW.Data, edit_state.TextW.Size, callback_data.Buf, NULL);
|
||||||
edit_state.CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen()
|
edit_state.CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen()
|
||||||
edit_state.CursorAnimReset();
|
edit_state.CursorAnimReset();
|
||||||
@ -11138,7 +11155,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|||||||
if (apply_new_text)
|
if (apply_new_text)
|
||||||
{
|
{
|
||||||
IM_ASSERT(apply_new_text_length >= 0);
|
IM_ASSERT(apply_new_text_length >= 0);
|
||||||
if (backup_current_text_length != apply_new_text_length && (flags & ImGuiInputTextFlags_CallbackResize))
|
if (backup_current_text_length != apply_new_text_length && is_resizable)
|
||||||
{
|
{
|
||||||
ImGuiInputTextCallbackData callback_data;
|
ImGuiInputTextCallbackData callback_data;
|
||||||
callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize;
|
callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize;
|
||||||
|
8
imgui.h
8
imgui.h
@ -1419,7 +1419,7 @@ struct ImGuiStorage
|
|||||||
// The callback function should return 0 by default.
|
// The callback function should return 0 by default.
|
||||||
// Special processing:
|
// Special processing:
|
||||||
// - ImGuiInputTextFlags_CallbackCharFilter: return 1 if the character is not allowed. You may also set 'EventChar=0' as any character replacement are allowed.
|
// - ImGuiInputTextFlags_CallbackCharFilter: return 1 if the character is not allowed. You may also set 'EventChar=0' as any character replacement are allowed.
|
||||||
// - ImGuiInputTextFlags_CallbackResize: BufTextLen is set to the new desired string length so you can allocate or update the size on your side of the fence. No need to initialize new characters or zero-terminator as InputText will do it.
|
// - ImGuiInputTextFlags_CallbackResize: notified by InputText() when the string is resized. BufTextLen is set to the new desired string length so you can update the string size on your side of the fence. You can also replace Buf pointer if your underlying data is reallocated. No need to initialize new characters or zero-terminator as InputText will do it right after the resize callback.
|
||||||
struct ImGuiInputTextCallbackData
|
struct ImGuiInputTextCallbackData
|
||||||
{
|
{
|
||||||
ImGuiInputTextFlags EventFlag; // One ImGuiInputTextFlags_Callback* // Read-only
|
ImGuiInputTextFlags EventFlag; // One ImGuiInputTextFlags_Callback* // Read-only
|
||||||
@ -1427,7 +1427,8 @@ struct ImGuiInputTextCallbackData
|
|||||||
void* UserData; // What user passed to InputText() // Read-only
|
void* UserData; // What user passed to InputText() // Read-only
|
||||||
|
|
||||||
// Arguments for the different callback events
|
// Arguments for the different callback events
|
||||||
// (If you modify the 'buf' contents make sure you update 'BufTextLen' and set 'BufDirty' to true!)
|
// - To modify the text buffer in a callback, prefer using the InsertChars() / DeleteChars() function. InsertChars() will take care of calling the resize callback if necessary.
|
||||||
|
// - If you know your edits are not going to resize the underlying buffer allocation, you may modify the contents of 'Buf[]' directly. You need to update 'BufTextLen' accordingly (0 <= BufTextLen < BufSize) and set 'BufDirty'' to true so InputText can update its internal state.
|
||||||
ImWchar EventChar; // Character input // Read-write // [CharFilter] Replace character or set to zero. return 1 is equivalent to setting EventChar=0;
|
ImWchar EventChar; // Character input // Read-write // [CharFilter] Replace character or set to zero. return 1 is equivalent to setting EventChar=0;
|
||||||
ImGuiKey EventKey; // Key pressed (Up/Down/TAB) // Read-only // [Completion,History]
|
ImGuiKey EventKey; // Key pressed (Up/Down/TAB) // Read-only // [Completion,History]
|
||||||
char* Buf; // Text buffer // Read-write // [Resize] Can replace pointer / [Completion,History,Always] Only write to pointed data, don't replace the actual pointer!
|
char* Buf; // Text buffer // Read-write // [Resize] Can replace pointer / [Completion,History,Always] Only write to pointed data, don't replace the actual pointer!
|
||||||
@ -1438,7 +1439,8 @@ struct ImGuiInputTextCallbackData
|
|||||||
int SelectionStart; // // Read-write // [Completion,History,Always] == to SelectionEnd when no selection)
|
int SelectionStart; // // Read-write // [Completion,History,Always] == to SelectionEnd when no selection)
|
||||||
int SelectionEnd; // // Read-write // [Completion,History,Always]
|
int SelectionEnd; // // Read-write // [Completion,History,Always]
|
||||||
|
|
||||||
// NB: Helper functions for text manipulation. Calling those function loses selection.
|
// Helper functions for text manipulation.
|
||||||
|
// Use those function to benefit from the CallbackResize behaviors. Calling those function reset the selection.
|
||||||
ImGuiInputTextCallbackData();
|
ImGuiInputTextCallbackData();
|
||||||
IMGUI_API void DeleteChars(int pos, int bytes_count);
|
IMGUI_API void DeleteChars(int pos, int bytes_count);
|
||||||
IMGUI_API void InsertChars(int pos, const char* text, const char* text_end = NULL);
|
IMGUI_API void InsertChars(int pos, const char* text, const char* text_end = NULL);
|
||||||
|
@ -36,7 +36,6 @@
|
|||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
|
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
|
||||||
#define snprintf _snprintf
|
|
||||||
#define vsnprintf _vsnprintf
|
#define vsnprintf _vsnprintf
|
||||||
#endif
|
#endif
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
@ -2809,14 +2808,15 @@ struct ExampleAppConsole
|
|||||||
bool reclaim_focus = false;
|
bool reclaim_focus = false;
|
||||||
if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), ImGuiInputTextFlags_EnterReturnsTrue|ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_CallbackHistory, &TextEditCallbackStub, (void*)this))
|
if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), ImGuiInputTextFlags_EnterReturnsTrue|ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_CallbackHistory, &TextEditCallbackStub, (void*)this))
|
||||||
{
|
{
|
||||||
Strtrim(InputBuf);
|
char* s = InputBuf;
|
||||||
if (InputBuf[0])
|
Strtrim(s);
|
||||||
ExecCommand(InputBuf);
|
if (s[0])
|
||||||
strcpy(InputBuf, "");
|
ExecCommand(s);
|
||||||
|
strcpy(s, "");
|
||||||
reclaim_focus = true;
|
reclaim_focus = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Demonstrate keeping focus on the input box
|
// Auto-focus on window apparition
|
||||||
ImGui::SetItemDefaultFocus();
|
ImGui::SetItemDefaultFocus();
|
||||||
if (reclaim_focus)
|
if (reclaim_focus)
|
||||||
ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
|
ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
|
||||||
@ -2959,9 +2959,9 @@ struct ExampleAppConsole
|
|||||||
// A better implementation would preserve the data on the current input line along with cursor position.
|
// A better implementation would preserve the data on the current input line along with cursor position.
|
||||||
if (prev_history_pos != HistoryPos)
|
if (prev_history_pos != HistoryPos)
|
||||||
{
|
{
|
||||||
int sz = (int)snprintf(data->Buf, (size_t)data->BufSize, "%s", (HistoryPos >= 0) ? History[HistoryPos] : "");
|
const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : "";
|
||||||
data->CursorPos = data->SelectionStart = data->SelectionEnd = data->BufTextLen = sz;
|
data->DeleteChars(0, data->BufTextLen);
|
||||||
data->BufDirty = true;
|
data->InsertChars(0, history_str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user