InputText: Add ImGuiInputTextFlags_CallbackEdit, selection helpers in ImGuiInputTextCallbackData(). Add simple InputText() callbacks demo.

This commit is contained in:
ocornut 2020-08-20 11:25:39 +02:00
parent 024993adf9
commit fc9ccad6b9
5 changed files with 82 additions and 4 deletions

View File

@ -37,8 +37,13 @@ HOW TO UPDATE?
Other Changes:
- InputText: Added selection helpers in ImGuiInputTextCallbackData().
- InputText: Added ImGuiInputTextFlags_CallbackEdit to modify internally owned buffer after an edit.
(note that InputText() already returns true on edit, the callback is useful mainly to manipulate the
underlying buffer while focus is active).
- DragFloat, DragScalar: Fixed ImGuiSliderFlags_ClampOnInput not being honored in the special case
where v_min == v_max. (#3361)
- Demo: Add simple InputText() callbacks demo (aside from the more elaborate ones in 'Examples->Console').
-----------------------------------------------------------------------

View File

@ -854,6 +854,7 @@ enum ImGuiInputTextFlags_
ImGuiInputTextFlags_NoUndoRedo = 1 << 16, // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID().
ImGuiInputTextFlags_CharsScientific = 1 << 17, // Allow 0123456789.+-*/eE (Scientific notation input)
ImGuiInputTextFlags_CallbackResize = 1 << 18, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this)
ImGuiInputTextFlags_CallbackEdit = 1 << 19, // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active)
// [Internal]
ImGuiInputTextFlags_Multiline = 1 << 20, // For internal use by InputTextMultiline()
ImGuiInputTextFlags_NoMarkEdited = 1 << 21 // For internal use by functions using InputText() before reformatting data
@ -1634,9 +1635,10 @@ struct ImGuiIO
// Shared state of InputText(), passed as an argument to your callback when a ImGuiInputTextFlags_Callback* flag is used.
// The callback function should return 0 by default.
// Callbacks (follow a flag name and see comments in ImGuiInputTextFlags_ declarations for more details)
// - ImGuiInputTextFlags_CallbackEdit: Callback on buffer edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active)
// - ImGuiInputTextFlags_CallbackAlways: Callback on each iteration
// - ImGuiInputTextFlags_CallbackCompletion: Callback on pressing TAB
// - ImGuiInputTextFlags_CallbackHistory: Callback on pressing Up/Down arrows
// - ImGuiInputTextFlags_CallbackAlways: Callback on each iteration
// - ImGuiInputTextFlags_CallbackCharFilter: Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard.
// - ImGuiInputTextFlags_CallbackResize: Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow.
struct ImGuiInputTextCallbackData
@ -1663,7 +1665,9 @@ struct ImGuiInputTextCallbackData
IMGUI_API ImGuiInputTextCallbackData();
IMGUI_API void DeleteChars(int pos, int bytes_count);
IMGUI_API void InsertChars(int pos, const char* text, const char* text_end = NULL);
bool HasSelection() const { return SelectionStart != SelectionEnd; }
void SelectAll() { SelectionStart = 0; SelectionEnd = BufTextLen; }
void ClearSelection() { SelectionStart = SelectionEnd = BufTextLen; }
bool HasSelection() const { return SelectionStart != SelectionEnd; }
};
// Resizing callback data to apply custom constraint. As enabled by SetNextWindowSizeConstraints(). Callback is called during the next Begin().

View File

@ -1177,8 +1177,11 @@ static void ShowDemoWindowWidgets()
static char buf4[64] = ""; ImGui::InputText("uppercase", buf4, 64, ImGuiInputTextFlags_CharsUppercase);
static char buf5[64] = ""; ImGui::InputText("no blank", buf5, 64, ImGuiInputTextFlags_CharsNoBlank);
static char buf6[64] = ""; ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters);
ImGui::TreePop();
}
ImGui::Text("Password input");
if (ImGui::TreeNode("Password Input"))
{
static char password[64] = "password123";
ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);
ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n");
@ -1187,6 +1190,62 @@ static void ShowDemoWindowWidgets()
ImGui::TreePop();
}
if (ImGui::TreeNode("Completion, History, Edit Callbacks"))
{
struct Funcs
{
static int MyCallback(ImGuiInputTextCallbackData* data)
{
if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion)
{
data->InsertChars(data->CursorPos, "..");
}
else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory)
{
if (data->EventKey == ImGuiKey_UpArrow)
{
data->DeleteChars(0, data->BufTextLen);
data->InsertChars(0, "Pressed Up!");
data->SelectAll();
}
else if (data->EventKey == ImGuiKey_DownArrow)
{
data->DeleteChars(0, data->BufTextLen);
data->InsertChars(0, "Pressed Down!");
data->SelectAll();
}
}
else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit)
{
// Toggle casing of first character
char c = data->Buf[0];
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32;
data->BufDirty = true;
// Increment a counter
int* p_int = (int*)data->UserData;
*p_int = *p_int + 1;
}
return 0;
}
};
static char buf1[64];
ImGui::InputText("Completion", buf1, 64, ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback);
ImGui::SameLine(); HelpMarker("Here we append \"..\" each time Tab is pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback.");
static char buf2[64];
ImGui::InputText("History", buf2, 64, ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback);
ImGui::SameLine(); HelpMarker("Here we replace and select text each time Up/Down are pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback.");
static char buf3[64];
static int edit_count = 0;
ImGui::InputText("Edit", buf3, 64, ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count);
ImGui::SameLine(); HelpMarker("Here we toggle the casing of the first character on every edits + count edits.");
ImGui::SameLine(); ImGui::Text("(%d)", edit_count);
ImGui::TreePop();
}
if (ImGui::TreeNode("Resize Callback"))
{
// To wire InputText() with std::string or any other custom string type,

View File

@ -858,6 +858,7 @@ struct IMGUI_API ImGuiInputTextState
float CursorAnim; // timer for cursor blink, reset on every user action so the cursor reappears immediately
bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!)
bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection
bool Edited; // edited this frame
ImGuiInputTextFlags UserFlags; // Temporarily set while we call user's callback
ImGuiInputTextCallback UserCallback; // "
void* UserCallbackData; // "

View File

@ -3514,6 +3514,7 @@ static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n)
ImWchar* dst = obj->TextW.Data + pos;
// We maintain our buffer length in both UTF-8 and wchar formats
obj->Edited = true;
obj->CurLenA -= ImTextCountUtf8BytesFromStr(dst, dst + n);
obj->CurLenW -= n;
@ -3548,6 +3549,7 @@ static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const Im
memmove(text + pos + new_text_len, text + pos, (size_t)(text_len - pos) * sizeof(ImWchar));
memcpy(text + pos, new_text, (size_t)new_text_len * sizeof(ImWchar));
obj->Edited = true;
obj->CurLenW += new_text_len;
obj->CurLenA += new_text_len_utf8;
obj->TextW[obj->CurLenW] = '\0';
@ -3946,6 +3948,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
{
IM_ASSERT(state != NULL);
backup_current_text_length = state->CurLenA;
state->Edited = false;
state->BufCapacityA = buf_size;
state->UserFlags = flags;
state->UserCallback = callback;
@ -4183,7 +4186,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
}
// User callback
if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackAlways)) != 0)
if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackAlways)) != 0)
{
IM_ASSERT(callback != NULL);
@ -4205,8 +4208,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
event_flag = ImGuiInputTextFlags_CallbackHistory;
event_key = ImGuiKey_DownArrow;
}
else if ((flags & ImGuiInputTextFlags_CallbackEdit) && state->Edited)
{
event_flag = ImGuiInputTextFlags_CallbackEdit;
}
else if (flags & ImGuiInputTextFlags_CallbackAlways)
{
event_flag = ImGuiInputTextFlags_CallbackAlways;
}
if (event_flag)
{