diff --git a/imgui.cpp b/imgui.cpp index e39f03bb7..abd26fcc7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7121,6 +7121,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const ImGuiID id = window->GetID(label); const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0; const bool is_editable = (flags & ImGuiInputTextFlags_ReadOnly) == 0; + const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), is_multiline ? ImGui::GetTextLineHeight() * 8.0f : label_size.y); // Arbitrary default of 8 lines high for multi-line @@ -7148,6 +7149,23 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 return false; } + // Password pushes a temporary font with only a fallback glyph + if (is_password) + { + const ImFont::Glyph* glyph = g.Font->FindGlyph('*'); + ImFont* password_font = &g.InputTextPasswordFont; + password_font->FontSize = g.Font->FontSize; + password_font->Scale = g.Font->Scale; + password_font->DisplayOffset = g.Font->DisplayOffset; + password_font->Ascent = g.Font->Ascent; + password_font->Descent = g.Font->Descent; + password_font->ContainerAtlas = g.Font->ContainerAtlas; + password_font->FallbackGlyph = glyph; + password_font->FallbackXAdvance = glyph->XAdvance; + IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexXAdvance.empty() && password_font->IndexLookup.empty()); + ImGui::PushFont(password_font); + } + // NB: we are only allowed to access 'edit_state' if we are the active widget. ImGuiTextEditState& edit_state = g.InputTextState; @@ -7318,7 +7336,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 else if (is_ctrl_only && IsKeyPressedMap(ImGuiKey_Z) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_UNDO); edit_state.ClearSelection(); } else if (is_ctrl_only && IsKeyPressedMap(ImGuiKey_Y) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_REDO); edit_state.ClearSelection(); } else if (is_ctrl_only && IsKeyPressedMap(ImGuiKey_A)) { edit_state.SelectAll(); edit_state.CursorFollow = true; } - else if (is_ctrl_only && ((IsKeyPressedMap(ImGuiKey_X) && is_editable) || IsKeyPressedMap(ImGuiKey_C)) && (!is_multiline || edit_state.HasSelection())) + else if (is_ctrl_only && !is_password && ((IsKeyPressedMap(ImGuiKey_X) && is_editable) || IsKeyPressedMap(ImGuiKey_C)) && (!is_multiline || edit_state.HasSelection())) { // Cut, Copy const bool cut = IsKeyPressedMap(ImGuiKey_X); @@ -7623,8 +7641,11 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 ImGui::EndGroup(); } + if (is_password) + ImGui::PopFont(); + // Log as text - if (g.LogEnabled) + if (g.LogEnabled && !is_password) LogRenderedText(render_pos, buf, NULL); if (label_size.x > 0) diff --git a/imgui.h b/imgui.h index db5af06af..aa56643b8 100644 --- a/imgui.h +++ b/imgui.h @@ -490,6 +490,7 @@ enum ImGuiInputTextFlags_ ImGuiInputTextFlags_NoHorizontalScroll = 1 << 12, // Disable following the cursor horizontally ImGuiInputTextFlags_AlwaysInsertMode = 1 << 13, // Insert mode ImGuiInputTextFlags_ReadOnly = 1 << 14, // Read-only mode + ImGuiInputTextFlags_Password = 1 << 15, // Password mode, display all characters as '*' // [Internal] ImGuiInputTextFlags_Multiline = 1 << 20 // For internal use by InputTextMultiline() }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 71aca37d3..559e81f50 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -417,6 +417,13 @@ void ImGui::ShowTestWindow(bool* opened) static char buf5[64] = ""; ImGui::InputText("no blank", buf5, 64, ImGuiInputTextFlags_CharsNoBlank); struct TextFilters { static int FilterImGuiLetters(ImGuiTextEditCallbackData* data) { if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar)) return 0; return 1; } }; static char buf6[64] = ""; ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); + + ImGui::Text("Password input"); + static char bufpass[64] = "password123"; + ImGui::InputText("password", bufpass, 64, ImGuiInputTextFlags_Password); + ImGui::SameLine(); ShowHelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n"); + ImGui::InputText("password (clear)", bufpass, 64); + ImGui::TreePop(); } diff --git a/imgui_internal.h b/imgui_internal.h index 4a4b8478c..a70e3caf4 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -395,6 +395,7 @@ struct ImGuiState // Widget state ImGuiTextEditState InputTextState; + ImFont InputTextPasswordFont; ImGuiID ScalarAsInputTextId; // Temporary text input when CTRL+clicking on a slider, etc. ImGuiStorage ColorEditModeStorage; // Store user selection of color edit mode ImVec2 ActiveClickDeltaToCenter;