diff --git a/imgui.h b/imgui.h index 2ffe14dd..748313ec 100644 --- a/imgui.h +++ b/imgui.h @@ -450,6 +450,7 @@ namespace ImGui // - Most of the ImGuiInputTextFlags flags are only useful for InputText() and not for InputFloatX, InputIntX, InputDouble etc. IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); IMGUI_API bool InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size = ImVec2(0,0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputTextWithHint(const char* label, const char* hint, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags flags = 0); IMGUI_API bool InputFloat2(const char* label, float v[2], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); IMGUI_API bool InputFloat3(const char* label, float v[3], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 45a21e48..1ecf49b8 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -481,10 +481,13 @@ static void ShowDemoWindowWidgets() { static char str0[128] = "Hello, world!"; - static int i0 = 123; ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0)); ImGui::SameLine(); ShowHelpMarker("USER:\nHold SHIFT or use mouse to select text.\n" "CTRL+Left/Right to word jump.\n" "CTRL+A or double-click to select all.\n" "CTRL+X,CTRL+C,CTRL+V clipboard.\n" "CTRL+Z,CTRL+Y undo/redo.\n" "ESCAPE to revert.\n\nPROGRAMMER:\nYou can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated in imgui_demo.cpp)."); + static char str1[128] = ""; + ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1)); + + static int i0 = 123; ImGui::InputInt("input int", &i0); ImGui::SameLine(); ShowHelpMarker("You can apply arithmetic operators +,*,/ on numerical values.\n e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\nUse +- to subtract.\n"); diff --git a/imgui_internal.h b/imgui_internal.h index 4f5ac884..576e3366 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1545,7 +1545,7 @@ namespace ImGui template IMGUI_API T RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, T v); // InputText - IMGUI_API bool InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format); // Color diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 543bcf8b..388d5547 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2692,7 +2692,7 @@ bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const c DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, data_ptr, format); ImStrTrimBlanks(data_buf); ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal); - bool value_changed = InputTextEx(label, data_buf, IM_ARRAYSIZE(data_buf), bb.GetSize(), flags); + bool value_changed = InputTextEx(label, NULL, data_buf, IM_ARRAYSIZE(data_buf), bb.GetSize(), flags); if (g.ScalarAsInputTextId == 0) { // First frame we started displaying the InputText widget, we expect it to take the active id. @@ -2883,9 +2883,10 @@ bool ImGui::InputDouble(const char* label, double* v, double step, double step_f } //------------------------------------------------------------------------- -// [SECTION] Widgets: InputText, InputTextMultiline +// [SECTION] Widgets: InputText, InputTextMultiline, InputTextWithHint //------------------------------------------------------------------------- // - InputText() +// - InputTextWithHint() // - InputTextMultiline() // - InputTextEx() [Internal] //------------------------------------------------------------------------- @@ -2893,12 +2894,17 @@ bool ImGui::InputDouble(const char* label, double* v, double step, double step_f bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) { IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() - return InputTextEx(label, buf, (int)buf_size, ImVec2(0,0), flags, callback, user_data); + return InputTextEx(label, NULL, buf, (int)buf_size, ImVec2(0,0), flags, callback, user_data); } bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) { - return InputTextEx(label, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data); + return InputTextEx(label, NULL, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data); +} + +bool ImGui::InputTextWithHint(const char* label, const char* hint, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + return InputTextEx(label, hint, buf, (int)buf_size, ImVec2(0,0), flags, callback, user_data); } static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end) @@ -3193,7 +3199,7 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f // - If you want to use ImGui::InputText() with std::string, see misc/cpp/imgui_stdlib.h // (FIXME: Rather confusing and messy function, among the worse part of our codebase, expecting to rewrite a V2 at some point.. Partly because we are // doing UTF8 > U16 > UTF8 conversions on the go to easily interface with stb_textedit. Ideally should stay in UTF-8 all the time. See https://github.com/nothings/stb/issues/188) -bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* callback_user_data) +bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* callback_user_data) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -3725,6 +3731,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const int buf_display_max_length = 2 * 1024 * 1024; const char* buf_display = NULL; const char* buf_display_end = NULL; + ImGuiCol text_color = ImGuiCol_COUNT; // Render text. We currently only render selection when the widget is active or while scrolling. // FIXME: We could remove the '&& render_cursor' to keep rendering selection when inactive. @@ -3861,11 +3868,26 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 } } + if (state->CurLenA != 0 || hint == NULL) + { + buf_display = (!is_readonly && state->TextAIsValid) ? state->TextA.Data : buf; + buf_display_end = buf_display + state->CurLenA; + text_color = ImGuiCol_Text; + } + else + { + buf_display = hint; + buf_display_end = hint + strlen(hint); + text_color = ImGuiCol_TextDisabled; + } + + // We test for 'buf_display_max_length' as a way to avoid some pathological cases (e.g. single-line 1 MB string) which would make ImDrawList crash. - buf_display = (!is_readonly && state->TextAIsValid) ? state->TextA.Data : buf; - buf_display_end = buf_display + state->CurLenA; if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length) - draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, GetColorU32(ImGuiCol_Text), buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); + { + IM_ASSERT(text_color != ImGuiCol_COUNT); + draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, GetColorU32(text_color), buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); + } // Draw blinking cursor if (render_cursor) @@ -3885,6 +3907,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 else { // Render text only (no selection, no cursor) + text_color = ImGuiCol_Text; buf_display = (g.ActiveId == id && !is_readonly && state->TextAIsValid) ? state->TextA.Data : buf; if (is_multiline) text_size = ImVec2(size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_display_end) * g.FontSize); // We don't need width @@ -3892,8 +3915,19 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 buf_display_end = buf_display + state->CurLenA; else buf_display_end = buf_display + strlen(buf_display); + + if (buf_display_end == buf_display && hint != NULL) + { + buf_display = hint; + buf_display_end = buf_display + strlen(buf_display); + text_color = ImGuiCol_TextDisabled; + } + if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length) - draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos, GetColorU32(ImGuiCol_Text), buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); + { + IM_ASSERT(text_color != ImGuiCol_COUNT); + draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos, GetColorU32(text_color), buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); + } } if (is_multiline) diff --git a/misc/cpp/imgui_stdlib.cpp b/misc/cpp/imgui_stdlib.cpp index 694813a4..fda60f4d 100644 --- a/misc/cpp/imgui_stdlib.cpp +++ b/misc/cpp/imgui_stdlib.cpp @@ -63,3 +63,15 @@ bool ImGui::InputTextMultiline(const char* label, std::string* str, const ImVec2 cb_user_data.ChainCallbackUserData = user_data; return InputTextMultiline(label, (char*)str->c_str(), str->capacity() + 1, size, flags, InputTextCallback, &cb_user_data); } + +bool ImGui::InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); + flags |= ImGuiInputTextFlags_CallbackResize; + + InputTextCallback_UserData cb_user_data; + cb_user_data.Str = str; + cb_user_data.ChainCallback = callback; + cb_user_data.ChainCallbackUserData = user_data; + return InputTextWithHint(label, hint, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data); +} diff --git a/misc/cpp/imgui_stdlib.h b/misc/cpp/imgui_stdlib.h index 06b06b9a..5bccb032 100644 --- a/misc/cpp/imgui_stdlib.h +++ b/misc/cpp/imgui_stdlib.h @@ -19,4 +19,5 @@ namespace ImGui // Because text input needs dynamic resizing, we need to setup a callback to grow the capacity IMGUI_API bool InputText(const char* label, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); IMGUI_API bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); }