diff --git a/CMakeLists.txt b/CMakeLists.txt index d8f9d4f..b9ee7a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,7 +76,6 @@ add_library(component STATIC include/ftxui/component/captured_mouse.hpp include/ftxui/component/component.hpp include/ftxui/component/component_base.hpp - include/ftxui/component/container.hpp include/ftxui/component/event.hpp include/ftxui/component/menu.hpp include/ftxui/component/mouse.hpp diff --git a/include/ftxui/component/container.hpp b/include/ftxui/component/container.hpp deleted file mode 100644 index 30f77f8..0000000 --- a/include/ftxui/component/container.hpp +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef FTXUI_COMPONENT_CONTAINER_HPP -#define FTXUI_COMPONENT_CONTAINER_HPP - -#include "ftxui/component/component.hpp" // for Component, Components -#include "ftxui/component/component_base.hpp" // for ComponentBase -#include "ftxui/component/event.hpp" // for Event -#include "ftxui/dom/elements.hpp" // for Element - -namespace ftxui { - -/// @brief A component where focus and events are automatically handled for you. -class ContainerBase : public ComponentBase { - public: - static Component Vertical(); - static Component Vertical(Components children); - static Component Vertical(Components children, int* selector); - - static Component Horizontal(); - static Component Horizontal(Components children); - static Component Horizontal(Components children, int* selector); - - static Component Tab(int* selector); - static Component Tab(Components children, int* selector); - - ~ContainerBase() override = default; - - // Component override. - bool OnEvent(Event event) override; - Element Render() override; - Component ActiveChild() override; - virtual void SetActiveChild(ComponentBase*) override; - - protected: - // Handlers - using EventHandler = bool (ContainerBase::*)(Event); - bool VerticalEvent(Event event); - bool HorizontalEvent(Event event); - bool TabEvent(Event) { return false; } - EventHandler event_handler_; - - using RenderHandler = Element (ContainerBase::*)(); - Element VerticalRender(); - Element HorizontalRender(); - Element TabRender(); - RenderHandler render_handler_; - - int selected_ = 0; - int* selector_ = nullptr; - bool is_tab_ = false; - - private: - bool OnMouseEvent(Event event); -}; - -} // namespace ftxui - -#endif /* end of include guard: FTXUI_COMPONENT_CONTAINER_HPP */ - -// 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. diff --git a/src/ftxui/component/container.cpp b/src/ftxui/component/container.cpp index e82fd36..297e055 100644 --- a/src/ftxui/component/container.cpp +++ b/src/ftxui/component/container.cpp @@ -5,10 +5,169 @@ #include // for move #include // for vector, __alloc_traits<>::value_type -#include "ftxui/component/container.hpp" +#include "ftxui/component/component.hpp" +#include "ftxui/component/event.hpp" namespace ftxui { +/// @brief A component where focus and events are automatically handled for you. +class ContainerBase : public ComponentBase { + public: + static Component Vertical() { return Vertical({}); } + static Component Vertical(Components children) { + return Vertical(std::move(children), /*selector=*/nullptr); + } + static Component Vertical(Components children, int* selector) { + auto container = std::make_shared(); + container->event_handler_ = &ContainerBase::VerticalEvent; + container->render_handler_ = &ContainerBase::VerticalRender; + container->selector_ = selector ? selector : &container->selected_; + for (Component& child : children) + container->Add(std::move(child)); + return container; + } + + static Component Horizontal() { return Horizontal({}); } + static Component Horizontal(Components children) { + return Horizontal(std::move(children), /*selector=*/nullptr); + } + static Component Horizontal(Components children, int* selector) { + auto container = std::make_shared(); + container->event_handler_ = &ContainerBase::HorizontalEvent; + container->render_handler_ = &ContainerBase::HorizontalRender; + container->selector_ = selector ? selector : &container->selected_; + for (Component& child : children) + container->Add(std::move(child)); + return container; + } + + static Component Tab(int* selector) { return Tab({}, selector); } + static Component Tab(Components children, int* selector) { + auto container = std::make_shared(); + container->selector_ = selector ? selector : &container->selected_; + container->event_handler_ = &ContainerBase::TabEvent; + container->render_handler_ = &ContainerBase::TabRender; + container->is_tab_ = true; + for (Component& child : children) + container->Add(std::move(child)); + return container; + } + + ~ContainerBase() override = default; + + // Component override. + bool OnEvent(Event event) override { + if (event.is_mouse()) + return OnMouseEvent(event); + + if (!Focused()) + return false; + + if (ActiveChild() && ActiveChild()->OnEvent(event)) + return true; + + return (this->*event_handler_)(event); + } + + Component ActiveChild() override { + if (children_.size() == 0) + return nullptr; + + return children_[*selector_ % children_.size()]; + } + + void SetActiveChild(ComponentBase* child) override { + for (size_t i = 0; i < children_.size(); ++i) { + if (children_[i].get() == child) { + *selector_ = i; + return; + } + } + } + + private: + // Handlers + + bool VerticalEvent(Event event) { + int old_selected = *selector_; + if (event == Event::ArrowUp || event == Event::Character('k')) + (*selector_)--; + if (event == Event::ArrowDown || event == Event::Character('j')) + (*selector_)++; + if (event == Event::Tab && children_.size()) + *selector_ = (*selector_ + 1) % children_.size(); + if (event == Event::TabReverse && children_.size()) + *selector_ = (*selector_ + children_.size() - 1) % children_.size(); + + *selector_ = std::max(0, std::min(int(children_.size()) - 1, *selector_)); + return old_selected != *selector_; + } + + bool HorizontalEvent(Event event) { + int old_selected = *selector_; + if (event == Event::ArrowLeft || event == Event::Character('h')) + (*selector_)--; + if (event == Event::ArrowRight || event == Event::Character('l')) + (*selector_)++; + if (event == Event::Tab && children_.size()) + *selector_ = (*selector_ + 1) % children_.size(); + if (event == Event::TabReverse && children_.size()) + *selector_ = (*selector_ + children_.size() - 1) % children_.size(); + + *selector_ = std::max(0, std::min(int(children_.size()) - 1, *selector_)); + return old_selected != *selector_; + } + + bool TabEvent(Event) { return false; } + + bool OnMouseEvent(Event event) { + if (is_tab_) + return ActiveChild()->OnEvent(event); + + for (Component& child : children_) { + if (child->OnEvent(event)) + return true; + } + return false; + } + + using EventHandler = bool (ContainerBase::*)(Event); + using RenderHandler = Element (ContainerBase::*)(); + + Element Render() override { return (this->*render_handler_)(); } + + Element VerticalRender() { + Elements elements; + for (auto& it : children_) + elements.push_back(it->Render()); + if (elements.size() == 0) + return text(L"Empty container"); + return vbox(std::move(elements)); + } + + Element HorizontalRender() { + Elements elements; + for (auto& it : children_) + elements.push_back(it->Render()); + if (elements.size() == 0) + return text(L"Empty container"); + return hbox(std::move(elements)); + } + + Element TabRender() { + Component active_child = ActiveChild(); + if (active_child) + return active_child->Render(); + return text(L"Empty container"); + } + + EventHandler event_handler_; + RenderHandler render_handler_; + int selected_ = 0; + int* selector_ = nullptr; + bool is_tab_ = false; +}; + namespace Container { /// @brief A list of components, drawn one by one vertically and navigated @@ -120,163 +279,6 @@ Component Tab(Components children, int* selector) { } // namespace Container -// static -Component ContainerBase::Vertical() { - return Vertical({}); -} - -// static -Component ContainerBase::Vertical(Components children) { - return Vertical(std::move(children), /*selector=*/nullptr); -} - -// static -Component ContainerBase::Vertical(Components children, int* selector) { - auto container = std::make_shared(); - container->event_handler_ = &ContainerBase::VerticalEvent; - container->render_handler_ = &ContainerBase::VerticalRender; - container->selector_ = selector ? selector : &container->selected_; - for (Component& child : children) - container->Add(std::move(child)); - return container; -} - -// static -Component ContainerBase::Horizontal() { - return Horizontal({}); -} - -// static -Component ContainerBase::Horizontal(Components children) { - return Horizontal(std::move(children), /*selector=*/nullptr); -} - -Component ContainerBase::Horizontal(Components children, int* selector) { - auto container = std::make_shared(); - container->event_handler_ = &ContainerBase::HorizontalEvent; - container->render_handler_ = &ContainerBase::HorizontalRender; - container->selector_ = selector ? selector : &container->selected_; - for (Component& child : children) - container->Add(std::move(child)); - return container; -} - -// static -Component ContainerBase::Tab(int* selector) { - return Tab({}, selector); -} - -// static -Component ContainerBase::Tab(Components children, int* selector) { - auto container = std::make_shared(); - container->selector_ = selector ? selector : &container->selected_; - container->event_handler_ = &ContainerBase::TabEvent; - container->render_handler_ = &ContainerBase::TabRender; - container->is_tab_ = true; - for (Component& child : children) - container->Add(std::move(child)); - return container; -} - -bool ContainerBase::OnEvent(Event event) { - if (event.is_mouse()) - return OnMouseEvent(event); - - if (!Focused()) - return false; - - if (ActiveChild() && ActiveChild()->OnEvent(event)) - return true; - - return (this->*event_handler_)(event); -} - -Component ContainerBase::ActiveChild() { - if (children_.size() == 0) - return nullptr; - - return children_[*selector_ % children_.size()]; -} - -void ContainerBase::SetActiveChild(ComponentBase* child) { - for (size_t i = 0; i < children_.size(); ++i) { - if (children_[i].get() == child) { - *selector_ = i; - return; - } - } -} - -bool ContainerBase::VerticalEvent(Event event) { - int old_selected = *selector_; - if (event == Event::ArrowUp || event == Event::Character('k')) - (*selector_)--; - if (event == Event::ArrowDown || event == Event::Character('j')) - (*selector_)++; - if (event == Event::Tab && children_.size()) - *selector_ = (*selector_ + 1) % children_.size(); - if (event == Event::TabReverse && children_.size()) - *selector_ = (*selector_ + children_.size() - 1) % children_.size(); - - *selector_ = std::max(0, std::min(int(children_.size()) - 1, *selector_)); - return old_selected != *selector_; -} - -bool ContainerBase::HorizontalEvent(Event event) { - int old_selected = *selector_; - if (event == Event::ArrowLeft || event == Event::Character('h')) - (*selector_)--; - if (event == Event::ArrowRight || event == Event::Character('l')) - (*selector_)++; - if (event == Event::Tab && children_.size()) - *selector_ = (*selector_ + 1) % children_.size(); - if (event == Event::TabReverse && children_.size()) - *selector_ = (*selector_ + children_.size() - 1) % children_.size(); - - *selector_ = std::max(0, std::min(int(children_.size()) - 1, *selector_)); - return old_selected != *selector_; -} - -Element ContainerBase::Render() { - return (this->*render_handler_)(); -} - -Element ContainerBase::VerticalRender() { - Elements elements; - for (auto& it : children_) - elements.push_back(it->Render()); - if (elements.size() == 0) - return text(L"Empty container"); - return vbox(std::move(elements)); -} - -Element ContainerBase::HorizontalRender() { - Elements elements; - for (auto& it : children_) - elements.push_back(it->Render()); - if (elements.size() == 0) - return text(L"Empty container"); - return hbox(std::move(elements)); -} - -Element ContainerBase::TabRender() { - Component active_child = ActiveChild(); - if (active_child) - return active_child->Render(); - return text(L"Empty container"); -} - -bool ContainerBase::OnMouseEvent(Event event) { - if (is_tab_) - return ActiveChild()->OnEvent(event); - - for (Component& child : children_) { - if (child->OnEvent(event)) - return true; - } - return false; -} - } // namespace ftxui // Copyright 2020 Arthur Sonzogni. All rights reserved. diff --git a/src/ftxui/component/container_test.cpp b/src/ftxui/component/container_test.cpp index 9c51c7b..7f50102 100644 --- a/src/ftxui/component/container_test.cpp +++ b/src/ftxui/component/container_test.cpp @@ -3,13 +3,14 @@ #include // for __shared_ptr_access, shared_ptr, allocator #include "ftxui/component/captured_mouse.hpp" // for ftxui -#include "ftxui/component/container.hpp" +#include "ftxui/component/component.hpp" // for AssertionResult, EXPECT_EQ, EXPECT_FALSE, EXPECT_TRUE, Test, TEST +#include "ftxui/component/event.hpp" // for AssertionResult, EXPECT_EQ, EXPECT_FALSE, EXPECT_TRUE, Test, TEST #include "gtest/gtest_pred_impl.h" // for AssertionResult, EXPECT_EQ, EXPECT_FALSE, EXPECT_TRUE, Test, TEST using namespace ftxui; TEST(ContainerTest, HorizontalEvent) { - auto container = ContainerBase::Horizontal(); + auto container = Container::Horizontal({}); auto c0 = Container::Horizontal({}); auto c1 = Container::Horizontal({}); auto c2 = Container::Horizontal({}); @@ -82,7 +83,7 @@ TEST(ContainerTest, HorizontalEvent) { } TEST(ContainerTest, VerticalEvent) { - auto container = ContainerBase::Vertical(); + auto container = Container::Vertical({}); auto c0 = Container::Horizontal({}); auto c1 = Container::Horizontal({}); auto c2 = Container::Horizontal({}); @@ -155,7 +156,7 @@ TEST(ContainerTest, VerticalEvent) { } TEST(ContainerTest, SetActiveChild) { - auto container = ContainerBase::Horizontal(); + auto container = Container::Horizontal({}); auto c0 = Container::Horizontal({}); auto c1 = Container::Horizontal({}); auto c2 = Container::Horizontal({}); @@ -209,16 +210,16 @@ TEST(ContainerTest, SetActiveChild) { } TEST(ContainerTest, TakeFocus) { - auto c = ContainerBase::Horizontal(); - auto c1 = ContainerBase::Vertical(); - auto c2 = ContainerBase::Vertical(); - auto c3 = ContainerBase::Vertical(); - auto c11 = ContainerBase::Horizontal(); - auto c12 = ContainerBase::Horizontal(); - auto c13 = ContainerBase::Horizontal(); - auto c21 = ContainerBase::Horizontal(); - auto c22 = ContainerBase::Horizontal(); - auto c23 = ContainerBase::Horizontal(); + auto c = Container::Horizontal({}); + auto c1 = Container::Vertical({}); + auto c2 = Container::Vertical({}); + auto c3 = Container::Vertical({}); + auto c11 = Container::Horizontal({}); + auto c12 = Container::Horizontal({}); + auto c13 = Container::Horizontal({}); + auto c21 = Container::Horizontal({}); + auto c22 = Container::Horizontal({}); + auto c23 = Container::Horizontal({}); c->Add(c1); c->Add(c2); diff --git a/src/ftxui/component/menu.cpp b/src/ftxui/component/menu.cpp index 0ff6b54..e621350 100644 --- a/src/ftxui/component/menu.cpp +++ b/src/ftxui/component/menu.cpp @@ -4,6 +4,7 @@ #include // for move #include "ftxui/component/captured_mouse.hpp" // for CapturedMouse +#include "ftxui/component/component.hpp" // for CapturedMouse #include "ftxui/component/event.hpp" // for Event, Event::ArrowDown, Event::ArrowUp, Event::Return, Event::Tab, Event::TabReverse #include "ftxui/component/menu.hpp" #include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Released