From 5ba29a9539a983fff187731366944e9bf2afdeb5 Mon Sep 17 00:00:00 2001
From: jdfa <kucherenko_a_v@ukr.net>
Date: Sat, 1 Oct 2022 14:34:15 +0300
Subject: [PATCH] #487 Handled Space and Enter events for Radiobox (#491)

Return true when an event a RadioBox is state change due to pressing Return or space.

Co-authored-by: ArthurSonzogni <sonzogniarthur@gmail.com>
---
 src/ftxui/component/radiobox.cpp      |   2 +-
 src/ftxui/component/radiobox_test.cpp | 233 ++++++++++++++++++--------
 2 files changed, 167 insertions(+), 68 deletions(-)

diff --git a/src/ftxui/component/radiobox.cpp b/src/ftxui/component/radiobox.cpp
index d55f2edc..72fcecb9 100644
--- a/src/ftxui/component/radiobox.cpp
+++ b/src/ftxui/component/radiobox.cpp
@@ -103,8 +103,8 @@ class RadioboxBase : public ComponentBase {
 
     if (event == Event::Character(' ') || event == Event::Return) {
       *selected_ = hovered_;
-      //*selected_ = focused_entry();
       option_->on_change();
+      return true;
     }
 
     return false;
diff --git a/src/ftxui/component/radiobox_test.cpp b/src/ftxui/component/radiobox_test.cpp
index ee9d12b8..294e2a94 100644
--- a/src/ftxui/component/radiobox_test.cpp
+++ b/src/ftxui/component/radiobox_test.cpp
@@ -11,106 +11,205 @@
 
 namespace ftxui {
 
-TEST(RadioboxTest, Navigation) {
+TEST(RadioboxTest, NavigationArrow) {
   int selected = 0;
   std::vector<std::string> entries = {"1", "2", "3"};
   auto radiobox = Radiobox(&entries, &selected);
 
-  // With arrow key.
+  // Down + Return
   EXPECT_EQ(selected, 0);
-  radiobox->OnEvent(Event::ArrowDown);
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::ArrowDown));
+  EXPECT_EQ(selected, 0);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 1);
+  EXPECT_TRUE(radiobox->OnEvent(Event::ArrowDown));
   EXPECT_EQ(selected, 1);
-  radiobox->OnEvent(Event::ArrowDown);
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 2);
+  EXPECT_FALSE(radiobox->OnEvent(Event::ArrowDown));
   EXPECT_EQ(selected, 2);
-  radiobox->OnEvent(Event::ArrowDown);
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 2);
+
+  // Up + Return
+  EXPECT_TRUE(radiobox->OnEvent(Event::ArrowUp));
   EXPECT_EQ(selected, 2);
-  radiobox->OnEvent(Event::ArrowUp);
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
   EXPECT_EQ(selected, 1);
-  radiobox->OnEvent(Event::ArrowUp);
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::ArrowUp));
+  EXPECT_EQ(selected, 1);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 0);
+  EXPECT_FALSE(radiobox->OnEvent(Event::ArrowUp));
   EXPECT_EQ(selected, 0);
-  radiobox->OnEvent(Event::ArrowUp);
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
   EXPECT_EQ(selected, 0);
+}
+
+TEST(RadioboxTest, NavigationArrowVim) {
+  int selected = 0;
+  std::vector<std::string> entries = {"1", "2", "3"};
+  auto radiobox = Radiobox(&entries, &selected);
 
-  // With vim like characters.
+  // J + Return
+  EXPECT_EQ(selected, 0);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Character('j')));
   EXPECT_EQ(selected, 0);
-  radiobox->OnEvent(Event::Character('j'));
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
   EXPECT_EQ(selected, 1);
-  radiobox->OnEvent(Event::Character('j'));
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Character('j')));
+  EXPECT_EQ(selected, 1);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 2);
+  EXPECT_FALSE(radiobox->OnEvent(Event::Character('j')));
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
   EXPECT_EQ(selected, 2);
-  radiobox->OnEvent(Event::Character('j'));
-  radiobox->OnEvent(Event::Return);
+
+  // K + Return
+  EXPECT_TRUE(radiobox->OnEvent(Event::Character('k')));
   EXPECT_EQ(selected, 2);
-  radiobox->OnEvent(Event::Character('k'));
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 1);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Character('k')));
   EXPECT_EQ(selected, 1);
-  radiobox->OnEvent(Event::Character('k'));
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 0);
+  EXPECT_FALSE(radiobox->OnEvent(Event::Character('k')));
   EXPECT_EQ(selected, 0);
-  radiobox->OnEvent(Event::Character('k'));
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
   EXPECT_EQ(selected, 0);
+}
 
-  // With more entries
-  entries = {"1", "2", "3"};
+TEST(RadioboxTest, NavigationTab) {
+  int selected = 0;
+  std::vector<std::string> entries = {"1", "2", "3"};
+  auto radiobox = Radiobox(&entries, &selected);
+
+  // Tab + Return
   EXPECT_EQ(selected, 0);
-  radiobox->OnEvent(Event::ArrowDown);
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Tab));
+  EXPECT_EQ(selected, 0);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 1);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Tab));
   EXPECT_EQ(selected, 1);
-  radiobox->OnEvent(Event::ArrowDown);
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
   EXPECT_EQ(selected, 2);
-  radiobox->OnEvent(Event::ArrowDown);
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Tab));
   EXPECT_EQ(selected, 2);
-  radiobox->OnEvent(Event::ArrowUp);
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 0);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Tab));
+  EXPECT_EQ(selected, 0);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 1);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Tab));
   EXPECT_EQ(selected, 1);
-  radiobox->OnEvent(Event::ArrowUp);
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 2);
+
+  // TabReverse + Return
+  EXPECT_TRUE(radiobox->OnEvent(Event::TabReverse));
+  EXPECT_EQ(selected, 2);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 1);
+  EXPECT_TRUE(radiobox->OnEvent(Event::TabReverse));
+  EXPECT_EQ(selected, 1);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
   EXPECT_EQ(selected, 0);
-  radiobox->OnEvent(Event::ArrowUp);
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::TabReverse));
   EXPECT_EQ(selected, 0);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 2);
+  EXPECT_TRUE(radiobox->OnEvent(Event::TabReverse));
+  EXPECT_EQ(selected, 2);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 1);
+  EXPECT_TRUE(radiobox->OnEvent(Event::TabReverse));
+  EXPECT_EQ(selected, 1);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+}
+
+TEST(RadioboxTest, NavigationHome) {
+  int selected = 0;
+  std::vector<std::string> entries = {"1", "2", "3"};
+  auto radiobox = Radiobox(&entries, &selected);
 
-  // With tab.
+  selected = 0;
+  EXPECT_FALSE(radiobox->OnEvent(Event::Home));
   EXPECT_EQ(selected, 0);
-  radiobox->OnEvent(Event::Tab);
-  radiobox->OnEvent(Event::Return);
+
+  selected = 1;
+  EXPECT_FALSE(radiobox->OnEvent(Event::Home));
   EXPECT_EQ(selected, 1);
-  radiobox->OnEvent(Event::Tab);
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 0);
+  EXPECT_FALSE(radiobox->OnEvent(Event::Home));
+  EXPECT_EQ(selected, 0);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 0);
+
+  selected = 2;
+  EXPECT_FALSE(radiobox->OnEvent(Event::Home));
   EXPECT_EQ(selected, 2);
-  radiobox->OnEvent(Event::Tab);
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
   EXPECT_EQ(selected, 0);
-  radiobox->OnEvent(Event::Tab);
-  radiobox->OnEvent(Event::Return);
-  EXPECT_EQ(selected, 1);
-  radiobox->OnEvent(Event::Tab);
-  radiobox->OnEvent(Event::Return);
+  EXPECT_FALSE(radiobox->OnEvent(Event::Home));
+  EXPECT_EQ(selected, 0);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 0);
+}
+
+TEST(RadioboxTest, NavigationEnd) {
+  int selected = 0;
+  std::vector<std::string> entries = {"1", "2", "3"};
+  auto radiobox = Radiobox(&entries, &selected);
+
+  selected = 0;
+  EXPECT_TRUE(radiobox->OnEvent(Event::End));
+  EXPECT_EQ(selected, 0);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 2);
+  EXPECT_FALSE(radiobox->OnEvent(Event::End));
+  EXPECT_EQ(selected, 2);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
   EXPECT_EQ(selected, 2);
-  radiobox->OnEvent(Event::TabReverse);
-  radiobox->OnEvent(Event::Return);
+
+  selected = 1;
+  EXPECT_FALSE(radiobox->OnEvent(Event::End));
   EXPECT_EQ(selected, 1);
-  radiobox->OnEvent(Event::TabReverse);
-  radiobox->OnEvent(Event::Return);
-  EXPECT_EQ(selected, 0);
-  radiobox->OnEvent(Event::TabReverse);
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 2);
+  EXPECT_FALSE(radiobox->OnEvent(Event::End));
+  EXPECT_EQ(selected, 2);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
+  EXPECT_EQ(selected, 2);
+
+  selected = 2;
+  EXPECT_FALSE(radiobox->OnEvent(Event::End));
+  EXPECT_EQ(selected, 2);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
   EXPECT_EQ(selected, 2);
-  radiobox->OnEvent(Event::TabReverse);
-  radiobox->OnEvent(Event::Return);
+}
+
+TEST(RadioboxTest, EventSpace) {
+  int selected = 0;
+  std::vector<std::string> entries = {"1", "2", "3"};
+  auto radiobox = Radiobox(&entries, &selected);
+
+  EXPECT_EQ(selected, 0);
+  EXPECT_TRUE(radiobox->OnEvent(Event::ArrowDown));
+  EXPECT_EQ(selected, 0);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Character(' ')));
   EXPECT_EQ(selected, 1);
-  radiobox->OnEvent(Event::TabReverse);
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::ArrowDown));
+  EXPECT_EQ(selected, 1);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Character(' ')));
+  EXPECT_EQ(selected, 2);
+  EXPECT_FALSE(radiobox->OnEvent(Event::ArrowDown));
+  EXPECT_EQ(selected, 2);
+  EXPECT_TRUE(radiobox->OnEvent(Event::Character(' ')));
+  EXPECT_EQ(selected, 2);
 }
 
 TEST(RadioboxTest, RemoveEntries) {
@@ -124,9 +223,9 @@ TEST(RadioboxTest, RemoveEntries) {
   EXPECT_EQ(selected, 0);
   EXPECT_EQ(focused_entry, 0);
 
-  radiobox->OnEvent(Event::ArrowDown);
-  radiobox->OnEvent(Event::ArrowDown);
-  radiobox->OnEvent(Event::Return);
+  EXPECT_TRUE(radiobox->OnEvent(Event::ArrowDown));
+  EXPECT_TRUE(radiobox->OnEvent(Event::ArrowDown));
+  EXPECT_TRUE(radiobox->OnEvent(Event::Return));
 
   EXPECT_EQ(selected, 2);
   EXPECT_EQ(focused_entry, 2);
-- 
GitLab