Add support for password for input element. (#158)

This fixes:
https://github.com/ArthurSonzogni/FTXUI/issues/139

CC:@Creapermann
This commit is contained in:
Arthur Sonzogni 2021-07-17 10:36:50 +02:00 committed by GitHub
parent 5ee4ec40de
commit b3a333b417
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 61 additions and 19 deletions

View File

@ -10,23 +10,31 @@
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;
std::wstring first_name_; std::wstring first_name;
std::wstring last_name_; std::wstring last_name;
std::wstring password;
Component input_first_name_ = Input(&first_name_, "first name");
Component input_last_name_ = Input(&last_name_, "last name"); Component input_first_name = Input(&first_name, "first name");
Component input_last_name = Input(&last_name, "last name");
InputOption password_option;
password_option.password = true;
Component input_password = Input(&password, "password", password_option);
auto component = Container::Vertical({ auto component = Container::Vertical({
input_first_name_, input_first_name,
input_last_name_, input_last_name,
input_password,
}); });
auto renderer = Renderer(component, [&] { auto renderer = Renderer(component, [&] {
return vbox({ return vbox({
text(L"Hello " + first_name_ + L" " + last_name_), text(L"Hello " + first_name + L" " + last_name),
separator(), separator(),
hbox({text(L" First name : "), input_first_name_->Render()}), hbox(text(L" First name : "), input_first_name->Render()),
hbox({text(L" Last name : "), input_last_name_->Render()}), hbox(text(L" Last name : "), input_last_name->Render()),
hbox(text(L" Password : "), input_password->Render()),
}) | }) |
border; border;
}); });

View File

@ -50,6 +50,9 @@ struct InputOption {
/// Called when the user presses enter. /// Called when the user presses enter.
std::function<void()> on_enter = [] {}; std::function<void()> on_enter = [] {};
/// Obscure the input content using '*'.
bool password = false;
Ref<int> cursor_position = 0; Ref<int> cursor_position = 0;
}; };

View File

@ -45,9 +45,7 @@ struct Pixel {
/// @brief Define how the Screen's dimensions should look like. /// @brief Define how the Screen's dimensions should look like.
/// @ingroup screen /// @ingroup screen
struct Dimension { struct Dimension {
/// coucou
static Dimension Fixed(int); static Dimension Fixed(int);
/// @brief coucou
static Dimension Fit(Element&); static Dimension Fit(Element&);
static Dimension Full(); static Dimension Full();

View File

@ -30,13 +30,18 @@ class InputBase : public ComponentBase {
// Component implementation: // Component implementation:
Element Render() override { Element Render() override {
std::wstring password_content;
if (option_->password)
password_content = std::wstring(content_->size(), U'');
std::wstring& content = option_->password ? password_content : *content_;
cursor_position() = cursor_position() =
std::max(0, std::min<int>(content_->size(), cursor_position())); std::max(0, std::min<int>(content.size(), cursor_position()));
auto main_decorator = flex | size(HEIGHT, EQUAL, 1); auto main_decorator = flex | size(HEIGHT, EQUAL, 1);
bool is_focused = Focused(); bool is_focused = Focused();
// placeholder. // placeholder.
if (content_->size() == 0) { if (content.size() == 0) {
if (is_focused) if (is_focused)
return text(*placeholder_) | focus | dim | inverted | main_decorator | return text(*placeholder_) | focus | dim | inverted | main_decorator |
reflect(input_box_); reflect(input_box_);
@ -46,15 +51,15 @@ class InputBase : public ComponentBase {
// Not focused. // Not focused.
if (!is_focused) if (!is_focused)
return text(*content_) | main_decorator | reflect(input_box_); return text(content) | main_decorator | reflect(input_box_);
std::wstring part_before_cursor = content_->substr(0, cursor_position()); std::wstring part_before_cursor = content.substr(0, cursor_position());
std::wstring part_at_cursor = cursor_position() < (int)content_->size() std::wstring part_at_cursor = cursor_position() < (int)content.size()
? content_->substr(cursor_position(), 1) ? content.substr(cursor_position(), 1)
: L" "; : L" ";
std::wstring part_after_cursor = std::wstring part_after_cursor =
cursor_position() < (int)content_->size() - 1 cursor_position() < (int)content.size() - 1
? content_->substr(cursor_position() + 1) ? content.substr(cursor_position() + 1)
: L""; : L"";
auto focused = is_focused ? focus : select; auto focused = is_focused ? focus : select;

View File

@ -35,6 +35,34 @@ TEST(InputTest, Type) {
input->OnEvent(Event::Character('b')); input->OnEvent(Event::Character('b'));
EXPECT_EQ(content, L"ab"); EXPECT_EQ(content, L"ab");
EXPECT_EQ(option.cursor_position(), 2u); EXPECT_EQ(option.cursor_position(), 2u);
auto document = input->Render();
auto screen = Screen::Create(Dimension::Fit(document));
Render(screen, document);
EXPECT_EQ(screen.PixelAt(0, 0).character, L"a");
EXPECT_EQ(screen.PixelAt(1, 0).character, L"b");
}
TEST(InputTest, TypePassword) {
std::wstring content;
std::wstring placeholder;
auto option = InputOption();
option.password = true;
Component input = Input(&content, &placeholder, &option);
input->OnEvent(Event::Character('a'));
EXPECT_EQ(content, L"a");
EXPECT_EQ(option.cursor_position(), 1u);
input->OnEvent(Event::Character('b'));
EXPECT_EQ(content, L"ab");
EXPECT_EQ(option.cursor_position(), 2u);
auto document = input->Render();
auto screen = Screen::Create(Dimension::Fit(document));
Render(screen, document);
EXPECT_EQ(screen.PixelAt(0, 0).character, L"");
EXPECT_EQ(screen.PixelAt(1, 0).character, L"");
} }
TEST(InputTest, Arrow) { TEST(InputTest, Arrow) {