Browse Source

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

ocornut 10 năm trước cách đây
mục cha
commit
9473cd491e
2 tập tin đã thay đổi với 93 bổ sung29 xóa
  1. 74 18
      imgui.cpp
  2. 19 11
      imgui.h

+ 74 - 18
imgui.cpp

@@ -129,6 +129,7 @@
  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.
  
+ - 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/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing()
  - 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;
 }
 
-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)))
-        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.
-        return true;
+        return false;
 
     if (flags & ImGuiInputTextFlags_CharsDecimal)
         if (!(c >= '0' && c <= '9') && (c != '.') && (c != '-') && (c != '+') && (c != '*') && (c != '/'))
-            return true;
+            return false;
 
     if (flags & ImGuiInputTextFlags_CharsHexadecimal)
         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
-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;
     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?)
             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)
                 {
                     // Insert character if they pass filtering
-                    if (InputTextFilterCharacter(c, flags))
+                    if (!InputTextFilterCharacter(&c, flags, callback, user_data))
                         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;
                         if (c >= 0x10000)
                             continue;
-                        if (InputTextFilterCharacter((ImWchar)c, flags))
+                        if (!InputTextFilterCharacter(&c, flags, callback, user_data))
                             continue;
                         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);
 
                 // 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;
                 if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && IsKeyPressedMap(ImGuiKey_Tab))
+                {
+                    event_flag = ImGuiInputTextFlags_CallbackCompletion;
                     event_key = ImGuiKey_Tab;
+                }
                 else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_UpArrow))
+                {
+                    event_flag = ImGuiInputTextFlags_CallbackHistory;
                     event_key = ImGuiKey_UpArrow;
+                }
                 else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_DownArrow))
+                {
+                    event_flag = ImGuiInputTextFlags_CallbackHistory;
                     event_key = ImGuiKey_DownArrow;
+                }
 
                 if (event_key != ImGuiKey_COUNT || (flags & ImGuiInputTextFlags_CallbackAlways) != 0)
                 {
                     ImGuiTextEditCallbackData callback_data;
+                    callback_data.EventFlag = event_flag; 
                     callback_data.EventKey = event_key;
                     callback_data.Buf = text_tmp_utf8;
                     callback_data.BufSize = edit_state.BufSize;
@@ -8313,6 +8342,33 @@ void ImGui::ShowTestWindow(bool* opened)
             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;
         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;
-        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);
-        switch (data->EventKey)
+        switch (data->EventFlag)
         {
-        case ImGuiKey_Tab:
+        case ImGuiInputTextFlags_CallbackCompletion:
             {
                 // Example of TEXT COMPLETION
 
@@ -9043,8 +9099,7 @@ struct ExampleAppConsole
 
                 break;
             }
-        case ImGuiKey_UpArrow:
-        case ImGuiKey_DownArrow:
+        case ImGuiInputTextFlags_CallbackHistory:
             {
                 // Example of HISTORY
                 const int prev_history_pos = HistoryPos;
@@ -9071,6 +9126,7 @@ struct ExampleAppConsole
                 }
             }
         }
+        return 0;
     }
 };
 

+ 19 - 11
imgui.h

@@ -44,6 +44,7 @@ typedef int ImGuiWindowFlags;       // enum ImGuiWindowFlags_
 typedef int ImGuiSetCondition;      // enum ImGuiSetCondition_
 typedef int ImGuiInputTextFlags;    // enum ImGuiInputTextFlags_
 struct ImGuiTextEditCallbackData;   // for advanced uses of InputText() 
+typedef int (*ImGuiTextEditCallback)(ImGuiTextEditCallbackData *data);
 
 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          RadioButton(const char* label, bool active);
     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          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);
@@ -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_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_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,
 };
 
@@ -716,15 +718,21 @@ struct ImGuiStorage
 // Shared state of InputText(), passed to callback when a ImGuiInputTextFlags_Callback* flag is used.
 struct ImGuiTextEditCallbackData
 {
-    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
-    ImGuiInputTextFlags Flags;          // What user passed to InputText()  // Read-only
-    int                 CursorPos;      //                                  // Read-write
-    int                 SelectionStart; //                                  // Read-write (== to SelectionEnd when no selection)
-    int                 SelectionEnd;   //                                  // Read-write
-    void*               UserData;       // What user passed to InputText()
+    ImGuiInputTextFlags EventFlag;      // One of ImGuiInputTextFlags_Callback* // Read-only
+    ImGuiInputTextFlags Flags;          // What user passed to InputText()      // Read-only
+    void*               UserData;       // What user passed to InputText()      // Read-only
+
+    // CharFilter event:
+    ImWchar             EventChar;      // Character input                      // Read-write (replace character or set to zero)
+
+    // Completion,History,Always events:
+    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.
     void DeleteChars(int pos, int bytes_count);