mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2024-11-26 20:47:05 +08:00
Improve ComponentBase and Container::Tab Focusable implementations (#341)
- Provide better defaults for ComponentBase `Focusable()` and `ActiveChild()` methods. This resolves: https://github.com/ArthurSonzogni/FTXUI/issues/335 - Implement `Container::Tab` 's `Focusable()` methods. This prevents the users to navigate into a tab with no interactivity.
This commit is contained in:
parent
f95ed885bb
commit
20f16b3984
@ -27,6 +27,9 @@ Element gaugeDirection(float ratio, GaugeDirection);
|
|||||||
### Component
|
### Component
|
||||||
- Support SIGTSTP. (ctrl+z).
|
- Support SIGTSTP. (ctrl+z).
|
||||||
- Support task posting. `ScreenInteractive::Post(Task)`.
|
- Support task posting. `ScreenInteractive::Post(Task)`.
|
||||||
|
- **bugfix** Container::Tab implements `Focusable()`.
|
||||||
|
- **bugfix** Improved default implementations of ComponentBase `Focusable()` and
|
||||||
|
`ActiveChild()` methods.
|
||||||
|
|
||||||
2.0.0
|
2.0.0
|
||||||
-----
|
-----
|
||||||
|
@ -105,7 +105,11 @@ bool ComponentBase::OnEvent(Event event) {
|
|||||||
/// @return the currently Active child.
|
/// @return the currently Active child.
|
||||||
/// @ingroup component
|
/// @ingroup component
|
||||||
Component ComponentBase::ActiveChild() {
|
Component ComponentBase::ActiveChild() {
|
||||||
return children_.empty() ? nullptr : children_.front();
|
for (auto& child : children_) {
|
||||||
|
if (child->Focusable())
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Return true when the component contains focusable elements.
|
/// @brief Return true when the component contains focusable elements.
|
||||||
@ -128,14 +132,15 @@ bool ComponentBase::Active() const {
|
|||||||
|
|
||||||
/// @brief Returns if the elements if focused by the user.
|
/// @brief Returns if the elements if focused by the user.
|
||||||
/// True when the ComponentBase is focused by the user. An element is Focused
|
/// True when the ComponentBase is focused by the user. An element is Focused
|
||||||
/// when it is with all its ancestors the ActiveChild() of their parents.
|
/// when it is with all its ancestors the ActiveChild() of their parents, and it
|
||||||
|
/// Focusable().
|
||||||
/// @ingroup component
|
/// @ingroup component
|
||||||
bool ComponentBase::Focused() const {
|
bool ComponentBase::Focused() const {
|
||||||
auto current = this;
|
auto current = this;
|
||||||
while (current && current->Active()) {
|
while (current && current->Active()) {
|
||||||
current = current->parent_;
|
current = current->parent_;
|
||||||
}
|
}
|
||||||
return !current;
|
return !current && Focusable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Make the |child| to be the "active" one.
|
/// @brief Make the |child| to be the "active" one.
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <memory> // for shared_ptr, __shared_ptr_access, allocator, make_shared
|
#include <memory> // for shared_ptr, __shared_ptr_access, allocator, make_shared
|
||||||
|
|
||||||
#include "ftxui/component/captured_mouse.hpp" // for ftxui
|
#include "ftxui/component/captured_mouse.hpp" // for ftxui
|
||||||
|
#include "ftxui/component/component.hpp" // for Make
|
||||||
#include "ftxui/component/component_base.hpp" // for ComponentBase, Component
|
#include "ftxui/component/component_base.hpp" // for ComponentBase, Component
|
||||||
#include "gtest/gtest_pred_impl.h" // for EXPECT_EQ, Test, SuiteApiResolver, TEST, TestFactoryImpl
|
#include "gtest/gtest_pred_impl.h" // for EXPECT_EQ, Test, SuiteApiResolver, TEST, TestFactoryImpl
|
||||||
|
|
||||||
@ -155,6 +156,22 @@ TEST(ContainerTest, ChildAt) {
|
|||||||
EXPECT_EQ(parent->ChildAt(0u), child_2);
|
EXPECT_EQ(parent->ChildAt(0u), child_2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ComponentTest, NonFocusableAreNotFocused) {
|
||||||
|
class NonFocusable : public ComponentBase {
|
||||||
|
bool Focusable() const override { return false; }
|
||||||
|
};
|
||||||
|
auto root = Make<NonFocusable>();
|
||||||
|
EXPECT_FALSE(root->Focused());
|
||||||
|
EXPECT_EQ(root->ActiveChild(), nullptr);
|
||||||
|
|
||||||
|
auto child = Make<NonFocusable>();
|
||||||
|
root->Add(child);
|
||||||
|
EXPECT_FALSE(root->Focused());
|
||||||
|
EXPECT_FALSE(child->Focused());
|
||||||
|
EXPECT_EQ(root->ActiveChild(), nullptr);
|
||||||
|
EXPECT_EQ(child->ActiveChild(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
||||||
// Use of this source code is governed by the MIT license that can be found in
|
// Use of this source code is governed by the MIT license that can be found in
|
||||||
// the LICENSE file.
|
// the LICENSE file.
|
||||||
|
@ -190,6 +190,12 @@ class TabContainer : public ContainerBase {
|
|||||||
return text("Empty container");
|
return text("Empty container");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Focusable() const override {
|
||||||
|
if (children_.size() == 0)
|
||||||
|
return false;
|
||||||
|
return children_[*selector_ % children_.size()]->Focusable();
|
||||||
|
}
|
||||||
|
|
||||||
bool OnMouseEvent(Event event) override {
|
bool OnMouseEvent(Event event) override {
|
||||||
return ActiveChild()->OnEvent(event);
|
return ActiveChild()->OnEvent(event);
|
||||||
}
|
}
|
||||||
|
@ -305,6 +305,34 @@ TEST(ContainerTest, TakeFocus) {
|
|||||||
EXPECT_FALSE(c23->Active());
|
EXPECT_FALSE(c23->Active());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ContainerTest, TabFocusable) {
|
||||||
|
int selected = 0;
|
||||||
|
auto c = Container::Tab(
|
||||||
|
{
|
||||||
|
Focusable(),
|
||||||
|
NonFocusable(),
|
||||||
|
Focusable(),
|
||||||
|
NonFocusable(),
|
||||||
|
},
|
||||||
|
&selected);
|
||||||
|
|
||||||
|
selected = 0;
|
||||||
|
EXPECT_TRUE(c->Focusable());
|
||||||
|
EXPECT_TRUE(c->Focused());
|
||||||
|
|
||||||
|
selected = 1;
|
||||||
|
EXPECT_FALSE(c->Focusable());
|
||||||
|
EXPECT_FALSE(c->Focused());
|
||||||
|
|
||||||
|
selected = 2;
|
||||||
|
EXPECT_TRUE(c->Focusable());
|
||||||
|
EXPECT_TRUE(c->Focused());
|
||||||
|
|
||||||
|
selected = 3;
|
||||||
|
EXPECT_FALSE(c->Focusable());
|
||||||
|
EXPECT_FALSE(c->Focused());
|
||||||
|
}
|
||||||
|
|
||||||
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
||||||
// Use of this source code is governed by the MIT license that can be found in
|
// Use of this source code is governed by the MIT license that can be found in
|
||||||
// the LICENSE file.
|
// the LICENSE file.
|
||||||
|
Loading…
Reference in New Issue
Block a user