diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7f002f30..1f928008 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -45,7 +45,9 @@ Other Changes: - Added GetBackgroundDrawList() helper to quickly get access to a ImDrawList that will be rendered behind every other windows. (#2391) - DragScalar, InputScalar, SliderScalar: Added support for u8/s8/u16/s16 data types. - We are reusing function instances for larger types to reduce code size. (#643, #320, #708, #1011) + We are reusing function instances of larger types to reduce code size. (#643, #320, #708, #1011) +- Added InputTextWithHint() to display a description/hint in the text box when no text + has been entered. (#2400) [@Organic-Code, @ocornut] - Nav: Fixed a tap on AltGR (e.g. German keyboard) from navigating to the menu layer. - Nav: Fixed Ctrl+Tab keeping active InputText() of a previous window active after the switch. (#2380) - Fixed IsItemDeactivated()/IsItemDeactivatedAfterEdit() from not correctly returning true diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 1ecf49b8..f8f23c2f 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -770,6 +770,7 @@ static void ShowDemoWindowWidgets() // Expose flags as checkbox for the demo static ImGuiComboFlags flags = 0; ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", (unsigned int*)&flags, ImGuiComboFlags_PopupAlignLeft); + ImGui::SameLine(); ShowHelpMarker("Only makes a difference if the popup is larger than the combo"); if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", (unsigned int*)&flags, ImGuiComboFlags_NoArrowButton)) flags &= ~ImGuiComboFlags_NoPreview; // Clear the other flag, as we cannot combine both if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", (unsigned int*)&flags, ImGuiComboFlags_NoPreview)) @@ -934,6 +935,7 @@ static void ShowDemoWindowWidgets() static char bufpass[64] = "password123"; ImGui::InputText("password", bufpass, 64, ImGuiInputTextFlags_Password | ImGuiInputTextFlags_CharsNoBlank); ImGui::SameLine(); ShowHelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n"); + ImGui::InputTextWithHint("password (w/ hint)", "", bufpass, 64, ImGuiInputTextFlags_Password | ImGuiInputTextFlags_CharsNoBlank); ImGui::InputText("password (clear)", bufpass, 64, ImGuiInputTextFlags_CharsNoBlank); ImGui::TreePop(); @@ -2177,7 +2179,7 @@ static void ShowDemoWindowPopups() // We can also use OpenPopupOnItemClick() which is the same as BeginPopupContextItem() but without the Begin call. // So here we will make it that clicking on the text field with the right mouse button (1) will toggle the visibility of the popup above. - ImGui::Text("(You can also right-click me to the same popup as above.)"); + ImGui::Text("(You can also right-click me to open the same popup as above.)"); ImGui::OpenPopupOnItemClick("item context menu", 1); // When used after an item that has an ID (here the Button), we can skip providing an ID to BeginPopupContextItem(). diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 388d5547..bb514efc 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2904,7 +2904,8 @@ bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, co 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); + IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() + 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) @@ -3364,8 +3365,18 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ bool value_changed = false; bool enter_pressed = false; + // Select the buffer to render. + const char* buf_display = ((render_cursor || render_selection || g.ActiveId == id) && !is_readonly && state->TextAIsValid) ? state->TextA.Data : buf; + const char* buf_display_end = NULL; // We have specialized paths below for setting the length + const bool is_displaying_hint = (hint != NULL && buf_display[0] == 0); + if (is_displaying_hint) + { + buf_display = hint; + buf_display_end = hint + strlen(hint); + } + // Password pushes a temporary font with only a fallback glyph - if (is_password) + if (is_password && !is_displaying_hint) { const ImFontGlyph* glyph = g.Font->FindGlyph('*'); ImFont* password_font = &g.InputTextPasswordFont; @@ -3729,14 +3740,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // without any carriage return, which would makes ImFont::RenderText() reserve too many vertices and probably crash. Avoid it altogether. // Note that we only use this limit on single-line InputText(), so a pathologically large line on a InputTextMultiline() would still crash. 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. if (render_cursor || render_selection) { + if (!is_displaying_hint) + buf_display_end = buf_display + state->CurLenA; + // Render text (with cursor and selection) // This is going to be messy. We need to: // - Display the text (this alone can be more easily clipped) @@ -3868,25 +3879,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } } - 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. if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length) { - 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); + ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text); + draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); } // Draw blinking cursor @@ -3907,26 +3904,17 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ 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 - else if (g.ActiveId == id) + else if (!is_displaying_hint && g.ActiveId == id) buf_display_end = buf_display + state->CurLenA; - else + else if (!is_displaying_hint) 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) { - 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); + ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text); + draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); } } @@ -3937,11 +3925,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ EndGroup(); } - if (is_password) + if (is_password && !is_displaying_hint) PopFont(); // Log as text - if (g.LogEnabled && !is_password) + if (g.LogEnabled && !(is_password && !is_displaying_hint)) LogRenderedText(&draw_pos, buf_display, buf_display_end); if (label_size.x > 0)