InputText(): added ImGuiInputTextFlags_CallbackCharFilter system for filtering/replacement. Callback now passed an "EventFlag" parameter.

This commit is contained in:
ocornut 2015-02-11 17:39:13 +00:00
parent 183a27fd70
commit 9473cd491e
2 changed files with 93 additions and 29 deletions

View File

@ -129,6 +129,7 @@
Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix. Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix.
Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code.
- 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now.
- 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior
- 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing() - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing()
- 2015/02/01 (1.31) - removed IO.MemReallocFn (unused) - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused)
@ -5223,27 +5224,44 @@ void ImGuiTextEditCallbackData::InsertChars(int pos, const char* new_text, const
SelectionStart = SelectionEnd = CursorPos; SelectionStart = SelectionEnd = CursorPos;
} }
static bool InputTextFilterCharacter(ImWchar c, ImGuiInputTextFlags flags) // Return false to discard a character.
static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
{ {
unsigned int c = *p_char;
if (c < 128 && c != ' ' && !isprint((int)(c & 0xFF))) if (c < 128 && c != ' ' && !isprint((int)(c & 0xFF)))
return true; return false;
if (c >= 0xE000 && c <= 0xF8FF) // Filter private Unicode range. I don't imagine anybody would want to input them. GLFW on OSX seems to send private characters for special keys like arrow keys. if (c >= 0xE000 && c <= 0xF8FF) // Filter private Unicode range. I don't imagine anybody would want to input them. GLFW on OSX seems to send private characters for special keys like arrow keys.
return true; return false;
if (flags & ImGuiInputTextFlags_CharsDecimal) if (flags & ImGuiInputTextFlags_CharsDecimal)
if (!(c >= '0' && c <= '9') && (c != '.') && (c != '-') && (c != '+') && (c != '*') && (c != '/')) if (!(c >= '0' && c <= '9') && (c != '.') && (c != '-') && (c != '+') && (c != '*') && (c != '/'))
return true; return false;
if (flags & ImGuiInputTextFlags_CharsHexadecimal) if (flags & ImGuiInputTextFlags_CharsHexadecimal)
if (!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F')) if (!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F'))
return true; return false;
return false; if (flags & ImGuiInputTextFlags_CallbackCharFilter)
{
ImGuiTextEditCallbackData callback_data;
memset(&callback_data, 0, sizeof(ImGuiTextEditCallbackData));
callback_data.EventFlag = ImGuiInputTextFlags_CallbackCharFilter;
callback_data.EventChar = c;
callback_data.Flags = flags;
callback_data.UserData = user_data;
callback(&callback_data);
*p_char = callback_data.EventChar;
if (!callback_data.EventChar)
return false;
}
return true;
} }
// Edit a string of text // Edit a string of text
bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, void (*callback)(ImGuiTextEditCallbackData*), void* user_data) bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
{ {
ImGuiState& g = *GImGui; ImGuiState& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
@ -5344,13 +5362,13 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT
// Process text input (before we check for Return because using some IME will effectively send a Return?) // Process text input (before we check for Return because using some IME will effectively send a Return?)
for (int n = 0; n < IM_ARRAYSIZE(g.IO.InputCharacters) && g.IO.InputCharacters[n]; n++) for (int n = 0; n < IM_ARRAYSIZE(g.IO.InputCharacters) && g.IO.InputCharacters[n]; n++)
{ {
const ImWchar c = g.IO.InputCharacters[n]; unsigned int c = (unsigned int)g.IO.InputCharacters[n];
if (c) if (c)
{ {
// Insert character if they pass filtering // Insert character if they pass filtering
if (InputTextFilterCharacter(c, flags)) if (!InputTextFilterCharacter(&c, flags, callback, user_data))
continue; continue;
edit_state.OnKeyPressed(c); edit_state.OnKeyPressed((int)c);
} }
} }
@ -5407,7 +5425,7 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT
break; break;
if (c >= 0x10000) if (c >= 0x10000)
continue; continue;
if (InputTextFilterCharacter((ImWchar)c, flags)) if (!InputTextFilterCharacter(&c, flags, callback, user_data))
continue; continue;
clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c; clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;
} }
@ -5442,17 +5460,28 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT
IM_ASSERT(callback != NULL); IM_ASSERT(callback != NULL);
// The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment. // The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment.
ImGuiInputTextFlags event_flag = 0;
ImGuiKey event_key = ImGuiKey_COUNT; ImGuiKey event_key = ImGuiKey_COUNT;
if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && IsKeyPressedMap(ImGuiKey_Tab)) if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && IsKeyPressedMap(ImGuiKey_Tab))
{
event_flag = ImGuiInputTextFlags_CallbackCompletion;
event_key = ImGuiKey_Tab; event_key = ImGuiKey_Tab;
}
else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_UpArrow)) else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_UpArrow))
{
event_flag = ImGuiInputTextFlags_CallbackHistory;
event_key = ImGuiKey_UpArrow; event_key = ImGuiKey_UpArrow;
}
else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_DownArrow)) else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_DownArrow))
{
event_flag = ImGuiInputTextFlags_CallbackHistory;
event_key = ImGuiKey_DownArrow; event_key = ImGuiKey_DownArrow;
}
if (event_key != ImGuiKey_COUNT || (flags & ImGuiInputTextFlags_CallbackAlways) != 0) if (event_key != ImGuiKey_COUNT || (flags & ImGuiInputTextFlags_CallbackAlways) != 0)
{ {
ImGuiTextEditCallbackData callback_data; ImGuiTextEditCallbackData callback_data;
callback_data.EventFlag = event_flag;
callback_data.EventKey = event_key; callback_data.EventKey = event_key;
callback_data.Buf = text_tmp_utf8; callback_data.Buf = text_tmp_utf8;
callback_data.BufSize = edit_state.BufSize; callback_data.BufSize = edit_state.BufSize;
@ -8313,6 +8342,33 @@ void ImGui::ShowTestWindow(bool* opened)
ImGui::TreePop(); ImGui::TreePop();
} }
if (ImGui::TreeNode("Filtered Text Input"))
{
static char buf1[64] = ""; ImGui::InputText("default", buf1, 64);
static char buf2[64] = ""; ImGui::InputText("decimal", buf2, 64, ImGuiInputTextFlags_CharsDecimal);
static char buf3[64] = ""; ImGui::InputText("hexadecimal", buf3, 64, ImGuiInputTextFlags_CharsHexadecimal);
struct TextFilters
{
static int FilterAZ(ImGuiTextEditCallbackData* data)
{
const ImWchar c = data->EventChar;
if (!((c >= 'a' && c <= 'z') || c >= 'A' && c <= 'Z'))
data->EventChar = 0;
return 0;
}
static int FilterUppercase(ImGuiTextEditCallbackData* data)
{
const ImWchar c = data->EventChar;
if (c >= 'a' && c <= 'z')
data->EventChar += 'A'-'a';
return 0;
}
};
static char buf4[64] = ""; ImGui::InputText("a-z only", buf4, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterAZ);
static char buf5[64] = ""; ImGui::InputText("uppercase", buf5, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterUppercase);
ImGui::TreePop();
}
static bool check = true; static bool check = true;
ImGui::Checkbox("checkbox", &check); ImGui::Checkbox("checkbox", &check);
@ -8967,18 +9023,18 @@ struct ExampleAppConsole
} }
} }
static void TextEditCallbackStub(ImGuiTextEditCallbackData* data) static int TextEditCallbackStub(ImGuiTextEditCallbackData* data)
{ {
ExampleAppConsole* console = (ExampleAppConsole*)data->UserData; ExampleAppConsole* console = (ExampleAppConsole*)data->UserData;
console->TextEditCallback(data); return console->TextEditCallback(data);
} }
void TextEditCallback(ImGuiTextEditCallbackData* data) int TextEditCallback(ImGuiTextEditCallbackData* data)
{ {
//AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd); //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd);
switch (data->EventKey) switch (data->EventFlag)
{ {
case ImGuiKey_Tab: case ImGuiInputTextFlags_CallbackCompletion:
{ {
// Example of TEXT COMPLETION // Example of TEXT COMPLETION
@ -9043,8 +9099,7 @@ struct ExampleAppConsole
break; break;
} }
case ImGuiKey_UpArrow: case ImGuiInputTextFlags_CallbackHistory:
case ImGuiKey_DownArrow:
{ {
// Example of HISTORY // Example of HISTORY
const int prev_history_pos = HistoryPos; const int prev_history_pos = HistoryPos;
@ -9071,6 +9126,7 @@ struct ExampleAppConsole
} }
} }
} }
return 0;
} }
}; };

30
imgui.h
View File

@ -44,6 +44,7 @@ typedef int ImGuiWindowFlags; // enum ImGuiWindowFlags_
typedef int ImGuiSetCondition; // enum ImGuiSetCondition_ typedef int ImGuiSetCondition; // enum ImGuiSetCondition_
typedef int ImGuiInputTextFlags; // enum ImGuiInputTextFlags_ typedef int ImGuiInputTextFlags; // enum ImGuiInputTextFlags_
struct ImGuiTextEditCallbackData; // for advanced uses of InputText() struct ImGuiTextEditCallbackData; // for advanced uses of InputText()
typedef int (*ImGuiTextEditCallback)(ImGuiTextEditCallbackData *data);
struct ImVec2 struct ImVec2
{ {
@ -275,7 +276,7 @@ namespace ImGui
IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value); IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value);
IMGUI_API bool RadioButton(const char* label, bool active); IMGUI_API bool RadioButton(const char* label, bool active);
IMGUI_API bool RadioButton(const char* label, int* v, int v_button); IMGUI_API bool RadioButton(const char* label, int* v, int v_button);
IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, void (*callback)(ImGuiTextEditCallbackData*) = NULL, void* user_data = NULL); IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL);
IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, int decimal_precision = -1, ImGuiInputTextFlags extra_flags = 0); IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, int decimal_precision = -1, ImGuiInputTextFlags extra_flags = 0);
IMGUI_API bool InputFloat2(const char* label, float v[2], int decimal_precision = -1); IMGUI_API bool InputFloat2(const char* label, float v[2], int decimal_precision = -1);
IMGUI_API bool InputFloat3(const char* label, float v[3], int decimal_precision = -1); IMGUI_API bool InputFloat3(const char* label, float v[3], int decimal_precision = -1);
@ -391,7 +392,8 @@ enum ImGuiInputTextFlags_
ImGuiInputTextFlags_EnterReturnsTrue = 1 << 3, // Return 'true' when Enter is pressed (as opposed to when the value was modified) ImGuiInputTextFlags_EnterReturnsTrue = 1 << 3, // Return 'true' when Enter is pressed (as opposed to when the value was modified)
ImGuiInputTextFlags_CallbackCompletion = 1 << 4, // Call user function on pressing TAB (for completion handling) ImGuiInputTextFlags_CallbackCompletion = 1 << 4, // Call user function on pressing TAB (for completion handling)
ImGuiInputTextFlags_CallbackHistory = 1 << 5, // Call user function on pressing Up/Down arrows (for history handling) ImGuiInputTextFlags_CallbackHistory = 1 << 5, // Call user function on pressing Up/Down arrows (for history handling)
ImGuiInputTextFlags_CallbackAlways = 1 << 6 // Call user function every time ImGuiInputTextFlags_CallbackAlways = 1 << 6, // Call user function every time
ImGuiInputTextFlags_CallbackCharFilter = 1 << 7 // Call user function to filter character. Modify data->EventChar to replace/filter input.
//ImGuiInputTextFlags_AlignCenter = 1 << 6, //ImGuiInputTextFlags_AlignCenter = 1 << 6,
}; };
@ -716,15 +718,21 @@ struct ImGuiStorage
// Shared state of InputText(), passed to callback when a ImGuiInputTextFlags_Callback* flag is used. // Shared state of InputText(), passed to callback when a ImGuiInputTextFlags_Callback* flag is used.
struct ImGuiTextEditCallbackData struct ImGuiTextEditCallbackData
{ {
ImGuiKey EventKey; // Key pressed (Up/Down/TAB) // Read-only ImGuiInputTextFlags EventFlag; // One of ImGuiInputTextFlags_Callback* // Read-only
char* Buf; // Current text // Read-write (pointed data only) ImGuiInputTextFlags Flags; // What user passed to InputText() // Read-only
size_t BufSize; // // Read-only void* UserData; // What user passed to InputText() // Read-only
bool BufDirty; // Set if you modify Buf directly // Write
ImGuiInputTextFlags Flags; // What user passed to InputText() // Read-only // CharFilter event:
int CursorPos; // // Read-write ImWchar EventChar; // Character input // Read-write (replace character or set to zero)
int SelectionStart; // // Read-write (== to SelectionEnd when no selection)
int SelectionEnd; // // Read-write // Completion,History,Always events:
void* UserData; // What user passed to InputText() ImGuiKey EventKey; // Key pressed (Up/Down/TAB) // Read-only
char* Buf; // Current text // Read-write (pointed data only)
size_t BufSize; // // Read-only
bool BufDirty; // Set if you modify Buf directly // Write
int CursorPos; // // Read-write
int SelectionStart; // // Read-write (== to SelectionEnd when no selection)
int SelectionEnd; // // Read-write
// NB: calling those function loses selection. // NB: calling those function loses selection.
void DeleteChars(int pos, int bytes_count); void DeleteChars(int pos, int bytes_count);