Allows components to remove a child or access to children in general (#152)

Allows components to remove a child or access to children in general.

Co-authored-by: Felix Heitmann <fheitmann@se-gpu-03.intern.plath.de>
Co-authored-by: ArthurSonzogni <sonzogniarthur@gmail.com>
This commit is contained in:
Felix Heitmann 2021-07-15 15:29:33 +02:00 committed by GitHub
parent 23789c2d7b
commit c34494ce26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 171 additions and 23 deletions

View File

@ -26,9 +26,13 @@ class ComponentBase {
ComponentBase() = default;
virtual ~ComponentBase();
// ComponentBase hierarchy.
// Component hierarchy:
ComponentBase* Parent();
Component& ChildAt(size_t i);
size_t ChildCount() const;
void Add(Component children);
void Detach();
void DetachAllChildren();
// Renders the component.
virtual Element Render();
@ -67,7 +71,6 @@ class ComponentBase {
private:
ComponentBase* parent_ = nullptr;
void Detach();
};
using Component = std::shared_ptr<ComponentBase>;

View File

@ -1,4 +1,6 @@
#include <stddef.h> // for size_t
#include <algorithm> // for find_if, max
#include <cassert> // for assert
#include <iterator> // for begin, end
#include <utility> // for move
@ -24,7 +26,6 @@ ComponentBase::~ComponentBase() {
}
/// @brief Return the parent ComponentBase, or nul if any.
/// @see Attach
/// @see Detach
/// @see Parent
/// @ingroup component
@ -32,7 +33,20 @@ ComponentBase* ComponentBase::Parent() {
return parent_;
}
/// @brief Add a children.
/// @brief Access the child at index `i`.
/// @ingroup component
Component& ComponentBase::ChildAt(size_t i) {
assert(i < ChildCount());
return children_[i];
}
/// @brief Returns the number of children.
/// @ingroup component
size_t ComponentBase::ChildCount() const {
return children_.size();
}
/// @brief Add a child.
/// @@param child The child to be attached.
/// @ingroup component
void ComponentBase::Add(Component child) {
@ -41,6 +55,29 @@ void ComponentBase::Add(Component child) {
children_.push_back(std::move(child));
}
/// @brief Detach this child from its parent.
/// @see Detach
/// @see Parent
/// @ingroup component
void ComponentBase::Detach() {
if (!parent_)
return;
auto it = std::find_if(std::begin(parent_->children_), //
std::end(parent_->children_), //
[this](const Component& that) { //
return this == that.get();
});
parent_->children_.erase(it);
parent_ = nullptr;
}
/// @brief Remove all children.
/// @ingroup component
void ComponentBase::DetachAllChildren() {
while (!children_.empty())
children_[0]->Detach();
}
/// @brief Draw the component.
/// Build a ftxui::Element to be drawn on the ftxi::Screen representing this
/// ftxui::ComponentBase.
@ -129,23 +166,6 @@ CapturedMouse ComponentBase::CaptureMouse(const Event& event) {
return event.screen_->CaptureMouse();
}
/// @brief Detach this children from its parent.
/// @see Attach
/// @see Detach
/// @see Parent
/// @ingroup component
void ComponentBase::Detach() {
if (!parent_)
return;
auto it = std::find_if(std::begin(parent_->children_), //
std::end(parent_->children_), //
[this](const Component& that) { //
return this == that.get();
});
parent_->children_.erase(it);
parent_ = nullptr;
}
} // namespace ftxui
// Copyright 2020 Arthur Sonzogni. All rights reserved.

View File

@ -1,8 +1,10 @@
#include <memory> // for shared_ptr, allocator, make_shared, __shared_ptr_access
#include <gtest/gtest-message.h> // for Message
#include <gtest/gtest-test-part.h> // for TestPartResult
#include <memory> // for shared_ptr, __shared_ptr_access, allocator, make_shared
#include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component_base.hpp" // for ComponentBase, Component
#include "gtest/gtest_pred_impl.h" // for Test, SuiteApiResolver, TEST, TestFactoryImpl
#include "gtest/gtest_pred_impl.h" // for EXPECT_EQ, Test, SuiteApiResolver, TEST, TestFactoryImpl
using namespace ftxui;
@ -30,6 +32,129 @@ TEST(ContainerTest, DeleteChildFirst) {
parent.reset();
}
TEST(ContainerTest, Detach) {
auto parent = Make();
auto child_1 = Make();
auto child_2 = Make();
auto child_3 = Make();
parent->Add(child_1);
parent->Add(child_2);
parent->Add(child_3);
EXPECT_EQ(parent->ChildCount(), 3u);
EXPECT_EQ(child_1->Parent(), parent.get());
EXPECT_EQ(child_2->Parent(), parent.get());
EXPECT_EQ(child_3->Parent(), parent.get());
child_2->Detach();
EXPECT_EQ(parent->ChildCount(), 2u);
EXPECT_EQ(child_1->Parent(), parent.get());
EXPECT_EQ(child_2->Parent(), nullptr);
EXPECT_EQ(child_3->Parent(), parent.get());
child_2->Detach();
EXPECT_EQ(parent->ChildCount(), 2u);
EXPECT_EQ(child_1->Parent(), parent.get());
EXPECT_EQ(child_2->Parent(), nullptr);
EXPECT_EQ(child_3->Parent(), parent.get());
child_1->Detach();
EXPECT_EQ(parent->ChildCount(), 1u);
EXPECT_EQ(child_1->Parent(), nullptr);
EXPECT_EQ(child_2->Parent(), nullptr);
EXPECT_EQ(child_3->Parent(), parent.get());
child_3->Detach();
EXPECT_EQ(parent->ChildCount(), 0u);
EXPECT_EQ(child_1->Parent(), nullptr);
EXPECT_EQ(child_2->Parent(), nullptr);
EXPECT_EQ(child_3->Parent(), nullptr);
}
TEST(ContainerTest, DetachAllChild) {
auto parent = Make();
auto child_1 = Make();
auto child_2 = Make();
auto child_3 = Make();
parent->Add(child_1);
parent->Add(child_2);
parent->Add(child_3);
EXPECT_EQ(parent->ChildCount(), 3u);
EXPECT_EQ(child_1->Parent(), parent.get());
EXPECT_EQ(child_2->Parent(), parent.get());
EXPECT_EQ(child_3->Parent(), parent.get());
parent->DetachAllChild();
EXPECT_EQ(parent->ChildCount(), 0u);
EXPECT_EQ(child_1->Parent(), nullptr);
EXPECT_EQ(child_2->Parent(), nullptr);
EXPECT_EQ(child_3->Parent(), nullptr);
}
TEST(ContainerTest, Add) {
auto parent = Make();
auto child_1 = Make();
auto child_2 = Make();
EXPECT_EQ(parent->ChildCount(), 0u);
EXPECT_EQ(child_1->Parent(), nullptr);
EXPECT_EQ(child_2->Parent(), nullptr);
parent->Add(child_1);
EXPECT_EQ(parent->ChildCount(), 1u);
EXPECT_EQ(child_1->Parent(), parent.get());
EXPECT_EQ(child_2->Parent(), nullptr);
parent->Add(child_1);
EXPECT_EQ(parent->ChildCount(), 1u);
EXPECT_EQ(child_1->Parent(), parent.get());
EXPECT_EQ(child_2->Parent(), nullptr);
parent->Add(child_2);
EXPECT_EQ(parent->ChildCount(), 2u);
EXPECT_EQ(child_1->Parent(), parent.get());
EXPECT_EQ(child_2->Parent(), parent.get());
}
TEST(ContainerTest, ChildAt) {
auto parent = Make();
auto child_1 = Make();
auto child_2 = Make();
EXPECT_EQ(parent->ChildCount(), 0u);
parent->Add(child_1);
EXPECT_EQ(parent->ChildCount(), 1u);
EXPECT_EQ(parent->ChildAt(0u), child_1);
parent->Add(child_2);
EXPECT_EQ(parent->ChildCount(), 2u);
EXPECT_EQ(parent->ChildAt(0u), child_1);
EXPECT_EQ(parent->ChildAt(1u), child_2);
parent->Add(child_1);
EXPECT_EQ(parent->ChildCount(), 2u);
EXPECT_EQ(parent->ChildAt(0u), child_2);
EXPECT_EQ(parent->ChildAt(1u), child_1);
child_1->Detach();
EXPECT_EQ(parent->ChildCount(), 1u);
EXPECT_EQ(parent->ChildAt(0u), child_2);
}
// Copyright 2020 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.