diff --git a/Userland/Libraries/LibGUI/TextBox.cpp b/Userland/Libraries/LibGUI/TextBox.cpp index c70d2cd862..b2a107524e 100644 --- a/Userland/Libraries/LibGUI/TextBox.cpp +++ b/Userland/Libraries/LibGUI/TextBox.cpp @@ -5,7 +5,9 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include +#include REGISTER_WIDGET(GUI, TextBox) REGISTER_WIDGET(GUI, PasswordBox) @@ -71,11 +73,59 @@ void TextBox::add_input_to_history(String input) m_history_index++; } +constexpr u32 password_box_substitution_code_point = '*'; + PasswordBox::PasswordBox() : TextBox() { - set_substitution_code_point('*'); + set_substitution_code_point(password_box_substitution_code_point); set_text_is_secret(true); + REGISTER_BOOL_PROPERTY("show_reveal_button", is_showing_reveal_button, set_show_reveal_button); +} + +Gfx::IntRect PasswordBox::reveal_password_button_rect() const +{ + constexpr i32 button_box_margin = 3; + auto button_box_size = height() - button_box_margin - button_box_margin; + return { width() - button_box_size - button_box_margin, button_box_margin, button_box_size, button_box_size }; +} + +void PasswordBox::paint_event(PaintEvent& event) +{ + TextBox::paint_event(event); + + if (is_showing_reveal_button()) { + auto button_rect = reveal_password_button_rect(); + + Painter painter(*this); + painter.add_clip_rect(event.rect()); + + auto icon_color = palette().button_text(); + if (substitution_code_point().has_value()) + icon_color = palette().disabled_text_front(); + + i32 dot_indicator_padding = height() / 5; + + Gfx::IntRect dot_indicator_rect = { button_rect.x() + dot_indicator_padding, button_rect.y() + dot_indicator_padding, button_rect.width() - dot_indicator_padding * 2, button_rect.height() - dot_indicator_padding * 2 }; + painter.fill_ellipse(dot_indicator_rect, icon_color); + + Gfx::IntPoint arc_start_point { dot_indicator_rect.x() - dot_indicator_padding / 2, dot_indicator_rect.y() + dot_indicator_padding / 2 }; + Gfx::IntPoint arc_end_point = { dot_indicator_rect.top_right().x() + dot_indicator_padding / 2, dot_indicator_rect.top_right().y() + dot_indicator_padding / 2 }; + Gfx::IntPoint arc_center_point = { dot_indicator_rect.center().x(), dot_indicator_rect.top() - dot_indicator_padding }; + painter.draw_quadratic_bezier_curve(arc_center_point, arc_start_point, arc_end_point, icon_color, 1); + } +} + +void PasswordBox::mousedown_event(GUI::MouseEvent& event) +{ + if (is_showing_reveal_button() && reveal_password_button_rect().contains(event.position())) { + Optional next_substitution_code_point; + if (!substitution_code_point().has_value()) + next_substitution_code_point = password_box_substitution_code_point; + set_substitution_code_point(next_substitution_code_point); + } else { + TextBox::mousedown_event(event); + } } UrlBox::UrlBox() diff --git a/Userland/Libraries/LibGUI/TextBox.h b/Userland/Libraries/LibGUI/TextBox.h index fc73af4d74..3ac2fb8a26 100644 --- a/Userland/Libraries/LibGUI/TextBox.h +++ b/Userland/Libraries/LibGUI/TextBox.h @@ -42,8 +42,23 @@ private: class PasswordBox : public TextBox { C_OBJECT(PasswordBox) +public: + bool is_showing_reveal_button() const { return m_show_reveal_button; } + void set_show_reveal_button(bool show) + { + m_show_reveal_button = show; + update(); + } + private: PasswordBox(); + + virtual void paint_event(PaintEvent&) override; + virtual void mousedown_event(GUI::MouseEvent&) override; + + Gfx::IntRect reveal_password_button_rect() const; + + bool m_show_reveal_button { false }; }; class UrlBox : public TextBox {