From dba019139b75f5946cbe007b37c1ed6a47714a1d Mon Sep 17 00:00:00 2001 From: Arthur Sonzogni Date: Sat, 12 Jan 2019 18:24:46 +0100 Subject: [PATCH] Refactor component containers. --- examples/component/input.cpp | 24 +++--- examples/component/menu.cpp | 7 +- examples/component/menu2.cpp | 22 +++--- examples/component/menu_style.cpp | 24 +++--- examples/component/tab.cpp | 20 ++--- examples/component/toggle.cpp | 39 ++++------ examples/dom/package_manager.cpp | 2 +- examples/dom/spinner.cpp | 2 +- examples/print_key_press.cpp | 11 ++- ftxui/CMakeLists.txt | 4 +- ftxui/include/ftxui/component/component.hpp | 63 +++++++--------- .../ftxui/component/component_direction.hpp | 24 ------ .../ftxui/component/component_horizontal.hpp | 18 ----- .../ftxui/component/component_vertical.hpp | 18 ----- ftxui/include/ftxui/component/container.hpp | 36 +++++++++ ftxui/include/ftxui/component/input.hpp | 4 +- ftxui/include/ftxui/component/menu.hpp | 3 +- .../ftxui/component/screen_interactive.hpp | 15 +--- ftxui/include/ftxui/component/toggle.hpp | 2 +- ftxui/include/ftxui/dom/elements.hpp | 12 ++- ftxui/include/ftxui/dom/take_any_args.hpp | 2 +- ftxui/src/ftxui/component/component.cpp | 64 ++++++++-------- .../ftxui/component/component_direction.cpp | 30 -------- .../ftxui/component/component_horizontal.cpp | 30 -------- .../ftxui/component/component_vertical.cpp | 30 -------- ftxui/src/ftxui/component/container.cpp | 73 +++++++++++++++++++ ftxui/src/ftxui/component/input.cpp | 5 +- ftxui/src/ftxui/component/menu.cpp | 2 - .../ftxui/component/screen_interactive.cpp | 71 ++++-------------- ftxui/src/ftxui/component/toggle.cpp | 5 +- ftxui/src/ftxui/dom/blink.cpp | 4 +- ftxui/src/ftxui/dom/bold.cpp | 4 +- ftxui/src/ftxui/dom/color.cpp | 12 +-- ftxui/src/ftxui/dom/dbox.cpp | 4 +- ftxui/src/ftxui/dom/dim.cpp | 4 +- ftxui/src/ftxui/dom/frame.cpp | 8 +- ftxui/src/ftxui/dom/hbox.cpp | 4 +- ftxui/src/ftxui/dom/inverted.cpp | 4 +- ftxui/src/ftxui/dom/node_decorator.hpp | 2 +- ftxui/src/ftxui/dom/underlined.cpp | 4 +- ftxui/src/ftxui/dom/vbox.cpp | 4 +- 41 files changed, 293 insertions(+), 423 deletions(-) delete mode 100644 ftxui/include/ftxui/component/component_direction.hpp delete mode 100644 ftxui/include/ftxui/component/component_horizontal.hpp delete mode 100644 ftxui/include/ftxui/component/component_vertical.hpp create mode 100644 ftxui/include/ftxui/component/container.hpp delete mode 100644 ftxui/src/ftxui/component/component_direction.cpp delete mode 100644 ftxui/src/ftxui/component/component_horizontal.cpp delete mode 100644 ftxui/src/ftxui/component/component_vertical.cpp create mode 100644 ftxui/src/ftxui/component/container.cpp diff --git a/examples/component/input.cpp b/examples/component/input.cpp index 66ac17c..2fb6c2b 100644 --- a/examples/component/input.cpp +++ b/examples/component/input.cpp @@ -1,31 +1,29 @@ -#include #include -#include -#include "ftxui/component/component_vertical.hpp" +#include "ftxui/component/container.hpp" #include "ftxui/component/input.hpp" #include "ftxui/component/screen_interactive.hpp" -#include "ftxui/util/string.hpp" +#include "ftxui/screen/string.hpp" using namespace ftxui; -class MyComponent : ComponentVertical { +class MyComponent : public Component { public: - MyComponent(Delegate* delegate) - : ComponentVertical(delegate), - input_1(delegate->NewChild()), - input_2(delegate->NewChild()), - input_3(delegate->NewChild()) { + MyComponent() { + Add(&container); + container.Add(&input_1); + container.Add(&input_2); + container.Add(&input_3); input_1.placeholder = L"input1"; input_2.placeholder = L"input2"; input_3.placeholder = L"input3"; - Focus(&input_1); } std::function on_enter = []() {}; private: + Container container = Container::Vertical(); Input input_1; Input input_2; Input input_3; @@ -44,7 +42,7 @@ class MyComponent : ComponentVertical { int main(int argc, const char* argv[]) { auto screen = ScreenInteractive::TerminalOutput(); - MyComponent component(screen.delegate()); + MyComponent component; component.on_enter = screen.ExitLoopClosure(); - screen.Loop(); + screen.Loop(&component); } diff --git a/examples/component/menu.cpp b/examples/component/menu.cpp index 4a75585..256a46d 100644 --- a/examples/component/menu.cpp +++ b/examples/component/menu.cpp @@ -8,10 +8,13 @@ int main(int argc, const char* argv[]) { using namespace ftxui; auto screen = ScreenInteractive::FixedSize(30, 3); - Menu menu(screen.delegate()); + + Menu menu; menu.entries = {L"entry 1", L"entry 2", L"entry 3"}; menu.selected = 0; menu.on_enter = screen.ExitLoopClosure(); - screen.Loop(); + screen.Loop(&menu); + + std::cout << "Selected element = " << menu.selected << std::endl; } diff --git a/examples/component/menu2.cpp b/examples/component/menu2.cpp index 03c26ab..0091dfb 100644 --- a/examples/component/menu2.cpp +++ b/examples/component/menu2.cpp @@ -2,20 +2,20 @@ #include #include -#include "ftxui/component/component_horizontal.hpp" -#include "ftxui/component/component_vertical.hpp" +#include "ftxui/component/container.hpp" #include "ftxui/component/menu.hpp" #include "ftxui/component/screen_interactive.hpp" -#include "ftxui/util/string.hpp" +#include "ftxui/screen/string.hpp" using namespace ftxui; -class MyComponent : ComponentHorizontal { +class MyComponent : public Component { public: - MyComponent(Delegate* delegate) - : ComponentHorizontal(delegate), - left_menu(delegate->NewChild()), - right_menu(delegate->NewChild()) { + MyComponent() { + Add(&container); + container.Add(&left_menu); + container.Add(&right_menu); + left_menu.entries = {L"0%", L"10%", L"20%", L"30%", L"40%", L"50%", L"60%", L"70%", L"80%", L"90%"}; right_menu.entries = {L"0%", L"1%", L"2%", L"3%", L"4%", L"5%", @@ -23,11 +23,11 @@ class MyComponent : ComponentHorizontal { left_menu.on_enter = [this]() { on_enter(); }; right_menu.on_enter = [this]() { on_enter(); }; - Focus(&left_menu); } std::function on_enter = [](){}; private: + Container container = Container::Horizontal(); Menu left_menu; Menu right_menu; @@ -66,7 +66,7 @@ class MyComponent : ComponentHorizontal { int main(int argc, const char *argv[]) { auto screen = ScreenInteractive::TerminalOutput(); - MyComponent component(screen.delegate()); + MyComponent component; component.on_enter = screen.ExitLoopClosure(); - screen.Loop(); + screen.Loop(&component); } diff --git a/examples/component/menu_style.cpp b/examples/component/menu_style.cpp index b770641..e6b347f 100644 --- a/examples/component/menu_style.cpp +++ b/examples/component/menu_style.cpp @@ -1,25 +1,20 @@ #include #include -#include "ftxui/component/component_horizontal.hpp" +#include "ftxui/component/container.hpp" #include "ftxui/component/menu.hpp" #include "ftxui/component/screen_interactive.hpp" -#include "ftxui/util/string.hpp" +#include "ftxui/screen/string.hpp" using namespace ftxui; -class MyComponent : ComponentHorizontal { +class MyComponent : public Component { public: - MyComponent(Delegate* delegate) - : ComponentHorizontal(delegate), - menu_1(delegate->NewChild()), - menu_2(delegate->NewChild()), - menu_3(delegate->NewChild()), - menu_4(delegate->NewChild()), - menu_5(delegate->NewChild()), - menu_6(delegate->NewChild()) { + MyComponent() { + Add(&container); for(Menu* menu : {&menu_1, &menu_2, &menu_3, &menu_4, &menu_5, &menu_6}) { + container.Add(menu); menu->entries = { L"Monkey", L"Dog", @@ -46,12 +41,11 @@ class MyComponent : ComponentHorizontal { menu_6.normal_style = dim | color(Color::Blue); menu_6.selected_style = color(Color::Blue); menu_6.active_style = bold | color(Color::Blue); - - Focus(&menu_1); } std::function on_enter = [](){}; private: + Container container = Container::Horizontal(); Menu menu_1; Menu menu_2; Menu menu_3; @@ -75,7 +69,7 @@ class MyComponent : ComponentHorizontal { int main(int argc, const char *argv[]) { auto screen = ScreenInteractive::TerminalOutput(); - MyComponent component(screen.delegate()); + MyComponent component; component.on_enter = screen.ExitLoopClosure(); - screen.Loop(); + screen.Loop(&component); } diff --git a/examples/component/tab.cpp b/examples/component/tab.cpp index 92d6f29..3b112d8 100644 --- a/examples/component/tab.cpp +++ b/examples/component/tab.cpp @@ -1,28 +1,28 @@ #include #include -#include "ftxui/component/component_vertical.hpp" +#include "ftxui/component/container.hpp" #include "ftxui/component/menu.hpp" #include "ftxui/component/screen_interactive.hpp" #include "ftxui/component/toggle.hpp" -#include "ftxui/util/string.hpp" +#include "ftxui/screen/string.hpp" using namespace ftxui; -class MyComponent : ComponentVertical { +class MyComponent : public Component { public: - MyComponent(Delegate* delegate) - : ComponentVertical(delegate), - toggle(delegate->NewChild()), - menu(delegate->NewChild()) { + MyComponent() { + Add(&container); + container.Add(&toggle); + container.Add(&menu); toggle.options = {L" left ", L" middle ", L" end "}; menu.entries = {L" top ", L" middle ", L" bottom "}; - Focus(&toggle); } std::function on_enter = [](){}; private: + Container container = Container::Vertical(); Toggle toggle; Menu menu; @@ -38,7 +38,7 @@ class MyComponent : ComponentVertical { int main(int argc, const char *argv[]) { auto screen = ScreenInteractive::TerminalOutput(); - MyComponent component(screen.delegate()); + MyComponent component; component.on_enter = screen.ExitLoopClosure(); - screen.Loop(); + screen.Loop(&component); } diff --git a/examples/component/toggle.cpp b/examples/component/toggle.cpp index 2fbda8d..84ecb1c 100644 --- a/examples/component/toggle.cpp +++ b/examples/component/toggle.cpp @@ -2,33 +2,32 @@ #include #include -#include "ftxui/component/component_horizontal.hpp" -#include "ftxui/component/component_vertical.hpp" +#include "ftxui/component/container.hpp" #include "ftxui/component/screen_interactive.hpp" #include "ftxui/component/toggle.hpp" -#include "ftxui/util/string.hpp" +#include "ftxui/screen/string.hpp" using namespace ftxui; -class MyComponent : ComponentVertical { +class MyComponent : public Component { public: - MyComponent(Delegate* delegate) - : ComponentVertical(delegate), - toggle_1(delegate->NewChild()), - toggle_2(delegate->NewChild()), - toggle_3(delegate->NewChild()), - toggle_4(delegate->NewChild()) { + MyComponent() { + Add(&container); + container.Add(&toggle_1); + container.Add(&toggle_2); + container.Add(&toggle_3); + container.Add(&toggle_4); + toggle_1.options = {L"On", L"Off"}; toggle_2.options = {L"Enabled", L"Disabled"}; toggle_3.options = {L"10€", L"0€"}; toggle_4.options = {L"Nothing", L"One element", L"Several elements"}; - - Focus(&toggle_1); } std::function on_enter = []() {}; private: + Container container = Container::Vertical(); Toggle toggle_1; Toggle toggle_2; Toggle toggle_3; @@ -45,23 +44,11 @@ class MyComponent : ComponentVertical { hbox(text(L" * Number of elements : "), toggle_4.Render()) ); } - - bool OnEvent(Event event) override { - if (ComponentVertical::OnEvent(event)) - return true; - - if (event == Event::Return) { - on_enter(); - return true; - } - - return false; - } }; int main(int argc, const char* argv[]) { auto screen = ScreenInteractive::TerminalOutput(); - MyComponent component(screen.delegate()); + MyComponent component; component.on_enter = screen.ExitLoopClosure(); - screen.Loop(); + screen.Loop(&component); } diff --git a/examples/dom/package_manager.cpp b/examples/dom/package_manager.cpp index a066d02..9cf0d32 100644 --- a/examples/dom/package_manager.cpp +++ b/examples/dom/package_manager.cpp @@ -4,7 +4,7 @@ #include "ftxui/dom/elements.hpp" #include "ftxui/screen/screen.hpp" -#include "ftxui/util/string.hpp" +#include "ftxui/screen/string.hpp" #include #include diff --git a/examples/dom/spinner.cpp b/examples/dom/spinner.cpp index a7d888f..b748e7e 100644 --- a/examples/dom/spinner.cpp +++ b/examples/dom/spinner.cpp @@ -4,7 +4,7 @@ #include "ftxui/screen/screen.hpp" #include "ftxui/dom/elements.hpp" -#include "ftxui/util/string.hpp" +#include "ftxui/screen/string.hpp" int main(int argc, const char *argv[]) { diff --git a/examples/print_key_press.cpp b/examples/print_key_press.cpp index fa66009..874126f 100644 --- a/examples/print_key_press.cpp +++ b/examples/print_key_press.cpp @@ -4,17 +4,16 @@ #include "ftxui/component/component.hpp" #include "ftxui/component/screen_interactive.hpp" -#include "ftxui/util/string.hpp" +#include "ftxui/screen/string.hpp" using namespace ftxui; class DrawKey : public Component { public: - DrawKey(Component::Delegate* delegate) - : Component(delegate) {} + ~DrawKey() override = default; Element Render() override { - Children children; + Elements children; for (size_t i = std::max(0, (int)keys.size() - 10); i < keys.size(); ++i) { std::string code = ""; for (size_t j = 0; j < 5; ++j) @@ -44,6 +43,6 @@ class DrawKey : public Component { int main(int argc, const char* argv[]) { auto screen = ScreenInteractive::FixedSize(80, 10); - DrawKey draw_key(screen.delegate()); - screen.Loop(); + DrawKey draw_key; + screen.Loop(&draw_key); } diff --git a/ftxui/CMakeLists.txt b/ftxui/CMakeLists.txt index f45da5b..075a254 100644 --- a/ftxui/CMakeLists.txt +++ b/ftxui/CMakeLists.txt @@ -31,9 +31,7 @@ add_library(dom add_library(component src/ftxui/component/component.cpp - src/ftxui/component/component_direction.cpp - src/ftxui/component/component_horizontal.cpp - src/ftxui/component/component_vertical.cpp + src/ftxui/component/container.cpp src/ftxui/component/event.cpp src/ftxui/component/input.cpp src/ftxui/component/menu.cpp diff --git a/ftxui/include/ftxui/component/component.hpp b/ftxui/include/ftxui/component/component.hpp index 351f792..c64d99d 100644 --- a/ftxui/include/ftxui/component/component.hpp +++ b/ftxui/include/ftxui/component/component.hpp @@ -13,50 +13,43 @@ class Focus; class Component { public: - class Delegate { - public: - Delegate() {} - virtual ~Delegate() {} - - // A Delegate shadows a component. - virtual void Register(Component* component) = 0; - virtual Component* component() = 0; - - // Create new children. - virtual Delegate* NewChild() = 0; - virtual std::vector children() = 0; - - // Navigate in the tree. - virtual Delegate* PreviousSibling() = 0; - virtual Delegate* NextSibling() = 0; - virtual Delegate* Parent() = 0; - virtual Delegate* Root() = 0; - }; - // Constructor/Destructor. - Component(Delegate* delegate); + Component() = default; virtual ~Component(); - // Render the component. + // Component hierarchy. + Component* Parent() { return parent_; } + void Add(Component* children); + + // Renders the component. virtual Element Render(); - // Handle an event. By default, it calls this function on each children. - virtual bool OnEvent(Event even); + // Handles an event. + // By default, reduce on children with a lazy OR. + // + // Returns whether the event was handled or not. + virtual bool OnEvent(Event); - // If this component contains children, this indicates which one is active. It - // can be none of them. - // We say an element has the focus if the chain of GetActiveChild() from the + // Focus management ---------------------------------------------------------- + // + // If this component contains children, this indicates which one is active, + // nullptr if none is active. + // + // We say an element has the focus if the chain of ActiveChild() from the // root component contains this object. - virtual Component* GetActiveChild() { return nullptr; } - bool Active(); // True is this component is an active child. - bool Focused(); // True if all the ancestors are active childs. + virtual Component* ActiveChild(); + // Whether this is the active child of its parent. + bool Active(); + // Whether all the ancestors are active. + bool Focused(); - Component* Parent(); - Component* PreviousSibling(); - Component* NextSibling(); - private: - Delegate* delegate_; + Component* parent_ = nullptr; + void Detach(); + void Attach(Component* parent); + + protected: + std::vector children_; }; } // namespace ftxui diff --git a/ftxui/include/ftxui/component/component_direction.hpp b/ftxui/include/ftxui/component/component_direction.hpp deleted file mode 100644 index ec3b23e..0000000 --- a/ftxui/include/ftxui/component/component_direction.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef FTXUI_COMPONENT_COMPONENT_DIRECTION_H_ -#define FTXUI_COMPONENT_COMPONENT_DIRECTION_H_ - -#include "ftxui/component/component.hpp" - -namespace ftxui { - -// A component where focus and events are automatically handled for you. -// Please use ComponentVertical or ComponentHorizontal. -class ComponentDirection : public Component { - public: - ComponentDirection(Delegate* delegate); - bool OnEvent(Event) override; - Component* GetActiveChild() override; - - protected: - void Focus(Component* child); - virtual bool HandleDirection(Event) = 0; - Component* active_child_; -}; - -} // namespace ftxui - -#endif /* end of include guard: FTXUI_COMPONENT_COMPONENT_DIRECTION_H_ */ diff --git a/ftxui/include/ftxui/component/component_horizontal.hpp b/ftxui/include/ftxui/component/component_horizontal.hpp deleted file mode 100644 index 5d3efe1..0000000 --- a/ftxui/include/ftxui/component/component_horizontal.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef FTXUI_COMPONENT_COMPONENT_HORIZONTAL_H_ -#define FTXUI_COMPONENT_COMPONENT_HORIZONTAL_H_ - -#include "ftxui/component/component_direction.hpp" - -namespace ftxui { - -// A component where focus and events are automatically handled for you. -// It assumes its children are put in the horizontal direction. -class ComponentHorizontal : public ComponentDirection { - public: - ComponentHorizontal(Delegate*); - bool HandleDirection(Event) override; -}; - -} // namespace ftxui - -#endif /* end of include guard: FTXUI_COMPONENT_COMPONENT_HORIZONTAL_H_ */ diff --git a/ftxui/include/ftxui/component/component_vertical.hpp b/ftxui/include/ftxui/component/component_vertical.hpp deleted file mode 100644 index cef6475..0000000 --- a/ftxui/include/ftxui/component/component_vertical.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef FTXUI_COMPONENT_COMPONENT_VERTICAL_H_ -#define FTXUI_COMPONENT_COMPONENT_VERTICAL_H_ - -#include "ftxui/component/component_direction.hpp" - -namespace ftxui { - -// A component where focus and events are automatically handled for you. -// It assumes its children are put in the vertical direction. -class ComponentVertical : public ComponentDirection { - public: - ComponentVertical(Delegate*); - bool HandleDirection(Event) override; -}; - -} // namespace ftxui - -#endif /* end of include guard: FTXUI_COMPONENT_COMPONENT_VERTICAL_H_ */ diff --git a/ftxui/include/ftxui/component/container.hpp b/ftxui/include/ftxui/component/container.hpp new file mode 100644 index 0000000..2e9d970 --- /dev/null +++ b/ftxui/include/ftxui/component/container.hpp @@ -0,0 +1,36 @@ +#ifndef FTXUI_COMPONENT_CONTAINER_HPP +#define FTXUI_COMPONENT_CONTAINER_HPP + +#include "ftxui/component/component.hpp" + +namespace ftxui { + +// A component where focus and events are automatically handled for you. +// List of container: +// +// Please use HorizontalContainer or VerticalContainer. +class Container : public Component { + public: + static Container Vertical(); + static Container Horizontal(); + + ~Container() override = default; + + // Component override. + bool OnEvent(Event event) override; + Component* ActiveChild() override; + protected: + // Handlers + using Handler = bool (Container::*)(Event); + Handler handler_; + bool Vertical(Event event); + bool Horizontal(Event event); + + size_t selected_ = 0; + + Container(Handler); +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_COMPONENT_CONTAINER_HPP */ diff --git a/ftxui/include/ftxui/component/input.hpp b/ftxui/include/ftxui/component/input.hpp index 132ac52..7616ff1 100644 --- a/ftxui/include/ftxui/component/input.hpp +++ b/ftxui/include/ftxui/component/input.hpp @@ -9,8 +9,8 @@ namespace ftxui { class Input : public Component { public: // Constructor. - Input(Delegate*); - ~Input() override; + Input() = default; + ~Input() override = default; // State. std::wstring content; diff --git a/ftxui/include/ftxui/component/menu.hpp b/ftxui/include/ftxui/component/menu.hpp index 4d9fe9f..1020194 100644 --- a/ftxui/include/ftxui/component/menu.hpp +++ b/ftxui/include/ftxui/component/menu.hpp @@ -10,7 +10,8 @@ namespace ftxui { class Menu : public Component { public: // Constructor. - Menu(Delegate*); + Menu() = default; + ~Menu() override = default; // State. std::vector entries = {}; diff --git a/ftxui/include/ftxui/component/screen_interactive.hpp b/ftxui/include/ftxui/component/screen_interactive.hpp index ae2e7b9..b69e313 100644 --- a/ftxui/include/ftxui/component/screen_interactive.hpp +++ b/ftxui/include/ftxui/component/screen_interactive.hpp @@ -1,31 +1,25 @@ #ifndef FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP #define FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP -#include "ftxui/component/component.hpp" #include "ftxui/screen/screen.hpp" #include #include namespace ftxui { +class Component; - -class ScreenInteractive : public ftxui::Screen { +class ScreenInteractive : public Screen { public: static ScreenInteractive FixedSize(size_t dimx, size_t dimy); static ScreenInteractive Fullscreen(); static ScreenInteractive TerminalOutput(); ~ScreenInteractive(); - void Loop(); + void Loop(Component*); std::function ExitLoopClosure(); - Component::Delegate* delegate(); - private: - class Delegate; - std::unique_ptr delegate_; - - void PrepareDraw(); + void Draw(Component* component); bool quit_ = false; enum class Dimension { @@ -34,7 +28,6 @@ class ScreenInteractive : public ftxui::Screen { Fullscreen, }; Dimension dimension_ = Dimension::Fixed; - ScreenInteractive(size_t dimx, size_t dimy, Dimension dimension); }; diff --git a/ftxui/include/ftxui/component/toggle.hpp b/ftxui/include/ftxui/component/toggle.hpp index 3773725..5d2628b 100644 --- a/ftxui/include/ftxui/component/toggle.hpp +++ b/ftxui/include/ftxui/component/toggle.hpp @@ -10,7 +10,7 @@ namespace ftxui { class Toggle : public Component { public: // Constructor. - Toggle(Delegate*); + ~Toggle() override = default; // State. size_t activated = 0; diff --git a/ftxui/include/ftxui/dom/elements.hpp b/ftxui/include/ftxui/dom/elements.hpp index e2672ad..6e6845f 100644 --- a/ftxui/include/ftxui/dom/elements.hpp +++ b/ftxui/include/ftxui/dom/elements.hpp @@ -9,15 +9,13 @@ namespace ftxui { using Element = std::unique_ptr; +using Elements = std::vector; using Decorator = std::function; -using Child = std::unique_ptr; -using Children = std::vector; -using Color = ftxui::Color; // --- Layout ---- -Element vbox(Children); -Element hbox(Children); -Element dbox(Children); +Element vbox(Elements); +Element hbox(Elements); +Element dbox(Elements); // -- Flexibility -- Element filler(); @@ -29,7 +27,7 @@ Element text(std::wstring text); Element separator(); Element gauge(float ratio); Element frame(Element); -Element window(Child title, Child content); +Element window(Element title, Element content); Element spinner(int charset_index, size_t image_index); // -- Decorator --- diff --git a/ftxui/include/ftxui/dom/take_any_args.hpp b/ftxui/include/ftxui/dom/take_any_args.hpp index 6e0ee61..cd97be6 100644 --- a/ftxui/include/ftxui/dom/take_any_args.hpp +++ b/ftxui/include/ftxui/dom/take_any_args.hpp @@ -2,7 +2,7 @@ // Turn a set of arguments into a vector. template -Children unpack(Args... args) { +Elements unpack(Args... args) { using T = std::common_type_t; std::vector vec; (vec.push_back(std::forward(args)), ...); diff --git a/ftxui/src/ftxui/component/component.cpp b/ftxui/src/ftxui/component/component.cpp index 7425198..a09a107 100644 --- a/ftxui/src/ftxui/component/component.cpp +++ b/ftxui/src/ftxui/component/component.cpp @@ -1,57 +1,53 @@ #include "ftxui/component/component.hpp" -#include "ftxui/component/delegate.hpp" #include namespace ftxui { +void Component::Detach() { if (!parent_) return; auto it = std::find(std::begin(parent_->children_), + std::end(parent_->children_), this); + parent_->children_.erase(it); -Component::Component(Delegate* delegate) { - delegate_ = delegate; - delegate_->Register(this); } -Component::~Component() {} +void Component::Attach(Component* parent) { + Detach(); + parent_ = parent; + parent_->children_.push_back(this); +} -Element Component::Render() { - using namespace ftxui; - return text(L"Not implemented component"); +void Component::Add(Component* child) { + child->Attach(this); +} + +Component::~Component() { + Detach(); } bool Component::OnEvent(Event event) { - return false; -} - -bool Component::Focused() { - Delegate* current = delegate_->Root(); - while (current) { - if (current == delegate_) + for(Component* child : children_) { + if (child->OnEvent(event)) return true; - - Component* active_child = current->component()->GetActiveChild(); - current = active_child ? active_child->delegate_ : nullptr; } return false; } -bool Component::Active() { - Delegate* parent = delegate_->Parent(); - return parent && parent->component()->GetActiveChild() == this; +Component* Component::ActiveChild() { + return children_.empty() ? nullptr : children_.front(); } -Component* Component::PreviousSibling() { - Delegate* sibling = delegate_->PreviousSibling(); - return sibling ? sibling->component() : nullptr; +Element Component::Render() { + return text(L"Not implemented component"); } -Component* Component::NextSibling() { - Delegate* sibling = delegate_->NextSibling(); - return sibling ? sibling->component() : nullptr; -} - -Component* Component::Parent() { - Delegate* parent_delegate = delegate_->Parent(); - if (!parent_delegate) - return nullptr; - return parent_delegate->component(); +bool Component::Focused() { + Component* current = this; + for(;;) { + Component* parent = current->parent_; + if (!parent) + return true; + if (parent->ActiveChild() != current) + return false; + current = parent; + } } } // namespace ftxui diff --git a/ftxui/src/ftxui/component/component_direction.cpp b/ftxui/src/ftxui/component/component_direction.cpp deleted file mode 100644 index da03b72..0000000 --- a/ftxui/src/ftxui/component/component_direction.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "ftxui/component/component_direction.hpp" - -namespace ftxui { - -ComponentDirection::ComponentDirection(Delegate* delegate) - : Component(delegate), active_child_(nullptr) {} - -bool ComponentDirection::OnEvent(Event event) { - if (!Focused()) - return false; - - if (!active_child_) - return false; - - if (active_child_->OnEvent(event)) - return true; - - return HandleDirection(event); - -} - -Component* ComponentDirection::GetActiveChild() { - return active_child_; -} - -void ComponentDirection::Focus(Component* child) { - active_child_ = child; -} - -} // namespace ftxui::Component diff --git a/ftxui/src/ftxui/component/component_horizontal.cpp b/ftxui/src/ftxui/component/component_horizontal.cpp deleted file mode 100644 index 20cd173..0000000 --- a/ftxui/src/ftxui/component/component_horizontal.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "ftxui/component/component_horizontal.hpp" - -namespace ftxui { - -ComponentHorizontal::ComponentHorizontal(Delegate* delegate) - : ComponentDirection(delegate) {} - -bool ComponentHorizontal::HandleDirection(Event event) { - // Left pressed ? - if (event == Event::ArrowLeft || event == Event::Character('h')) { - Component* previous_sibling = active_child_->PreviousSibling(); - if (previous_sibling) { - active_child_ = previous_sibling; - return true; - } - } - - // Left pressed ? - if (event == Event::ArrowRight || event == Event::Character('l')) { - Component* next_sibling = active_child_->NextSibling(); - if (next_sibling) { - active_child_ = next_sibling; - return true; - } - } - - return false; -} - -} // namespace ftxui diff --git a/ftxui/src/ftxui/component/component_vertical.cpp b/ftxui/src/ftxui/component/component_vertical.cpp deleted file mode 100644 index 1233303..0000000 --- a/ftxui/src/ftxui/component/component_vertical.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "ftxui/component/component_vertical.hpp" - -namespace ftxui { - -ComponentVertical::ComponentVertical(Delegate* delegate) - : ComponentDirection(delegate) {} - -bool ComponentVertical::HandleDirection(Event event) { - // Up pressed ? - if (event == Event::ArrowUp || event == Event::Character('k')) { - Component* previous_sibling = active_child_->PreviousSibling(); - if (previous_sibling) { - active_child_ = previous_sibling; - return true; - } - } - - // Down pressed ? - if (event == Event::ArrowDown || event == Event::Character('j')) { - Component* next_sibling = active_child_->NextSibling(); - if (next_sibling) { - active_child_ = next_sibling; - return true; - } - } - - return false; -} - -} // namespace ftxui diff --git a/ftxui/src/ftxui/component/container.cpp b/ftxui/src/ftxui/component/container.cpp new file mode 100644 index 0000000..19d0a3b --- /dev/null +++ b/ftxui/src/ftxui/component/container.cpp @@ -0,0 +1,73 @@ +#include "ftxui/component/container.hpp" + +namespace ftxui { + +// static +Container Container::Horizontal() { + return Container(&Container::Horizontal); +} + +// static +Container Container::Vertical() { + return Container(&Container::Vertical); +} + +Container::Container(Container::Handler handler) : handler_(handler) {} + +bool Container::OnEvent(Event event) { + if (!Focused()) + return false; + + if (ActiveChild()->OnEvent(event)) + return true; + + return (this->*handler_)(event); +} + +Component* Container::ActiveChild() { + return children_[selected_ % children_.size()]; +} + +bool Container::Vertical(Event event) { + selected_ %= children_.size(); + // Left pressed ? + if (event == Event::ArrowUp || event == Event::Character('k')) { + if (selected_ != 0) { + selected_--; + return true; + } + } + + // Left pressed ? + if (event == Event::ArrowDown || event == Event::Character('j')) { + if (selected_ != children_.size() - 1) { + selected_++; + return true; + } + } + + return false; +} + +bool Container::Horizontal(Event event) { + selected_ %= children_.size(); + // Left pressed ? + if (event == Event::ArrowLeft || event == Event::Character('h')) { + if (selected_ != 0) { + selected_--; + return true; + } + } + + // Left pressed ? + if (event == Event::ArrowRight || event == Event::Character('l')) { + if (selected_ != children_.size() - 1) { + selected_++; + return true; + } + } + + return false; +} + +} // namespace ftxui diff --git a/ftxui/src/ftxui/component/input.cpp b/ftxui/src/ftxui/component/input.cpp index b5f1109..8e9bb6f 100644 --- a/ftxui/src/ftxui/component/input.cpp +++ b/ftxui/src/ftxui/component/input.cpp @@ -1,11 +1,8 @@ #include "ftxui/component/input.hpp" -#include "ftxui/util/string.hpp" +#include "ftxui/screen/string.hpp" namespace ftxui { -Input::Input(Delegate* delegate): Component(delegate) {} -Input::~Input() {} - // Component implementation. Element Input::Render() { bool is_focused = Focused(); diff --git a/ftxui/src/ftxui/component/menu.cpp b/ftxui/src/ftxui/component/menu.cpp index c1bc75e..848460b 100644 --- a/ftxui/src/ftxui/component/menu.cpp +++ b/ftxui/src/ftxui/component/menu.cpp @@ -4,8 +4,6 @@ namespace ftxui { -Menu::Menu(Delegate* delegate) : Component(delegate) {} - Element Menu::Render() { std::vector elements; bool focused = Focused(); diff --git a/ftxui/src/ftxui/component/screen_interactive.cpp b/ftxui/src/ftxui/component/screen_interactive.cpp index 13284e7..c3fa104 100644 --- a/ftxui/src/ftxui/component/screen_interactive.cpp +++ b/ftxui/src/ftxui/component/screen_interactive.cpp @@ -45,53 +45,10 @@ Event GetEvent() { }; // namespace -class ScreenInteractive::Delegate : public Component::Delegate { - public: - Delegate() : root_(this) {} - - void Register(Component* c) override { component_ = c; } - - std::vector> child_; - Delegate* NewChild() override { - Delegate* child = new Delegate; - child->root_ = root_; - child->parent_ = this; - - if (!child_.empty()) { - child_.back()->next_sibling_ = child; - child->previous_sibling_ = child_.back().get(); - } - - child_.emplace_back(child); - return child; - } - - void OnEvent(Event event) { component_->OnEvent(event); } - - std::vector children() override { - std::vector ret; - for (auto& it : child_) - ret.push_back(it.get()); - return ret; - } - - Component::Delegate* root_; - Component::Delegate* parent_ = nullptr; - Component::Delegate* previous_sibling_ = nullptr; - Component::Delegate* next_sibling_ = nullptr; - Component* component_; - - Component::Delegate* Root() override { return root_; } - Component::Delegate* Parent() override { return parent_; } - Component::Delegate* PreviousSibling() override { return previous_sibling_; } - Component::Delegate* NextSibling() override { return next_sibling_; } - Component* component() override { return component_; } -}; - ScreenInteractive::ScreenInteractive(size_t dimx, size_t dimy, Dimension dimension) - : Screen(dimx, dimy), delegate_(new Delegate), dimension_(dimension) {} + : Screen(dimx, dimy), dimension_(dimension) {} ScreenInteractive::~ScreenInteractive() {} // static @@ -109,10 +66,10 @@ ScreenInteractive ScreenInteractive::TerminalOutput() { return ScreenInteractive(0, 0, Dimension::TerminalOutput); } -void ScreenInteractive::Loop() { - std::cout << "\033[?9h"; /* Send Mouse Row & Column on Button Press */ - std::cout << "\033[?1000h"; /* Send Mouse X & Y on button press and release */ - std::cout << std::flush; +void ScreenInteractive::Loop(Component* component) { + //std::cout << "\033[?9h"; [> Send Mouse Row & Column on Button Press <] + //std::cout << "\033[?1000h"; [> Send Mouse X & Y on button press and release <] + //std::cout << std::flush; // Save the old terminal configuration. struct termios terminal_configuration_old; @@ -130,23 +87,27 @@ void ScreenInteractive::Loop() { std::string reset_position; while (!quit_) { - PrepareDraw(); + Draw(component); std::cout << reset_position << ToString() << std::flush; reset_position = ResetPosition(); Clear(); - delegate_->OnEvent(GetEvent()); + component->OnEvent(GetEvent()); } // Restore the old terminal configuration. tcsetattr(STDIN_FILENO, TCSANOW, &terminal_configuration_old); + + std::cout << std::endl; } -void ScreenInteractive::PrepareDraw() { - auto document = delegate_->component()->Render(); +void ScreenInteractive::Draw(Component* component) { + auto document = component->Render(); size_t dimx; size_t dimy; switch (dimension_) { case Dimension::Fixed: + dimx = dimx_; + dimy = dimy_; break; case Dimension::TerminalOutput: document->ComputeRequirement(); @@ -161,8 +122,10 @@ void ScreenInteractive::PrepareDraw() { } if (dimx != dimx_ || dimy != dimy_) { + std::cerr << dimx_ << " " << dimy_ << std::endl; dimx_ = dimx; dimy_ = dimy; + std::cerr << dimx_ << " " << dimy_ << std::endl; pixels_ = std::vector>( dimy, std::vector(dimx)); } @@ -170,10 +133,6 @@ void ScreenInteractive::PrepareDraw() { Render(*this, document.get()); } -Component::Delegate* ScreenInteractive::delegate() { - return delegate_.get(); -} - std::function ScreenInteractive::ExitLoopClosure() { return [this]() { quit_ = true; }; } diff --git a/ftxui/src/ftxui/component/toggle.cpp b/ftxui/src/ftxui/component/toggle.cpp index c3d3ad4..f9a4348 100644 --- a/ftxui/src/ftxui/component/toggle.cpp +++ b/ftxui/src/ftxui/component/toggle.cpp @@ -2,13 +2,10 @@ namespace ftxui { -Toggle::Toggle(Delegate* delegate) : Component(delegate) {} - Element Toggle::Render() { auto highlight = Focused() ? inverted : bold; - Children children; - + Elements children; for(size_t i = 0; i blink(Child child) { +std::unique_ptr blink(Element child) { return std::make_unique(unpack(std::move(child))); } diff --git a/ftxui/src/ftxui/dom/bold.cpp b/ftxui/src/ftxui/dom/bold.cpp index 8cf20a4..33852ce 100644 --- a/ftxui/src/ftxui/dom/bold.cpp +++ b/ftxui/src/ftxui/dom/bold.cpp @@ -5,7 +5,7 @@ namespace ftxui { class Bold : public NodeDecorator { public: - Bold(Children children) : NodeDecorator(std::move(children)) {} + Bold(Elements children) : NodeDecorator(std::move(children)) {} ~Bold() override {} void Render(Screen& screen) override { @@ -18,7 +18,7 @@ class Bold : public NodeDecorator { } }; -std::unique_ptr bold(Child child) { +std::unique_ptr bold(Element child) { return std::make_unique(unpack(std::move(child))); } diff --git a/ftxui/src/ftxui/dom/color.cpp b/ftxui/src/ftxui/dom/color.cpp index 8c2beb3..e2e7d49 100644 --- a/ftxui/src/ftxui/dom/color.cpp +++ b/ftxui/src/ftxui/dom/color.cpp @@ -5,7 +5,7 @@ namespace ftxui { class BgColor : public NodeDecorator { public: - BgColor(Children children, Color color) + BgColor(Elements children, Color color) : NodeDecorator(std::move(children)), color_(color) {} void Render(Screen& screen) override { @@ -22,7 +22,7 @@ class BgColor : public NodeDecorator { class FgColor : public NodeDecorator { public: - FgColor(Children children, Color color) + FgColor(Elements children, Color color) : NodeDecorator(std::move(children)), color_(color) {} ~FgColor() override {} @@ -38,22 +38,22 @@ class FgColor : public NodeDecorator { Color color_; }; -std::unique_ptr color(Color c, Child child) { +std::unique_ptr color(Color c, Element child) { return std::make_unique(unpack(std::move(child)), c); } -std::unique_ptr bgcolor(Color c, Child child) { +std::unique_ptr bgcolor(Color c, Element child) { return std::make_unique(unpack(std::move(child)), c); } Decorator color(Color c) { - return [c](Child child) { + return [c](Element child) { return color(c, std::move(child)); }; } Decorator bgcolor(Color c) { - return [c](Child child) { + return [c](Element child) { return bgcolor(c, std::move(child)); }; } diff --git a/ftxui/src/ftxui/dom/dbox.cpp b/ftxui/src/ftxui/dom/dbox.cpp index fdbe652..f0b8afb 100644 --- a/ftxui/src/ftxui/dom/dbox.cpp +++ b/ftxui/src/ftxui/dom/dbox.cpp @@ -5,7 +5,7 @@ namespace ftxui { class DBox : public Node { public: - DBox(Children children) : Node(std::move(children)) {} + DBox(Elements children) : Node(std::move(children)) {} ~DBox() {} void ComputeRequirement() override { @@ -28,7 +28,7 @@ class DBox : public Node { } }; -std::unique_ptr dbox(Children children) { +std::unique_ptr dbox(Elements children) { return std::make_unique(std::move(children)); } diff --git a/ftxui/src/ftxui/dom/dim.cpp b/ftxui/src/ftxui/dom/dim.cpp index bf3aff2..a4fefdf 100644 --- a/ftxui/src/ftxui/dom/dim.cpp +++ b/ftxui/src/ftxui/dom/dim.cpp @@ -7,7 +7,7 @@ using ftxui::Screen; class Dim : public NodeDecorator { public: - Dim(Children children) : NodeDecorator(std::move(children)) {} + Dim(Elements children) : NodeDecorator(std::move(children)) {} ~Dim() override {} void Render(Screen& screen) override { @@ -20,7 +20,7 @@ class Dim : public NodeDecorator { } }; -std::unique_ptr dim(Child child) { +std::unique_ptr dim(Element child) { return std::make_unique(unpack(std::move(child))); } diff --git a/ftxui/src/ftxui/dom/frame.cpp b/ftxui/src/ftxui/dom/frame.cpp index 7053c98..7879470 100644 --- a/ftxui/src/ftxui/dom/frame.cpp +++ b/ftxui/src/ftxui/dom/frame.cpp @@ -9,7 +9,7 @@ static wchar_t charset[] = L"┌┐└┘─│┬┴┤├"; class Frame : public Node { public: - Frame(Children children) : Node(std::move(children)) {} + Frame(Elements children) : Node(std::move(children)) {} ~Frame() override {} void ComputeRequirement() override { @@ -81,16 +81,16 @@ class Frame : public Node { } }; -std::unique_ptr frame(Child child) { +std::unique_ptr frame(Element child) { return std::make_unique(unpack(std::move(child))); } -std::unique_ptr window(Child title, Child content) { +std::unique_ptr window(Element title, Element content) { return std::make_unique(unpack(std::move(content), std::move(title))); } Decorator boxed() { - return [](Child child) { + return [](Element child) { return frame(std::move(child)); }; } diff --git a/ftxui/src/ftxui/dom/hbox.cpp b/ftxui/src/ftxui/dom/hbox.cpp index 9fbef95..26d899c 100644 --- a/ftxui/src/ftxui/dom/hbox.cpp +++ b/ftxui/src/ftxui/dom/hbox.cpp @@ -5,7 +5,7 @@ namespace ftxui { class HBox : public Node { public: - HBox(Children children) : Node(std::move(children)) {} + HBox(Elements children) : Node(std::move(children)) {} ~HBox() {} void ComputeRequirement() override { @@ -59,7 +59,7 @@ class HBox : public Node { } }; -std::unique_ptr hbox(Children children) { +std::unique_ptr hbox(Elements children) { return std::make_unique(std::move(children)); } diff --git a/ftxui/src/ftxui/dom/inverted.cpp b/ftxui/src/ftxui/dom/inverted.cpp index 095aba2..23763bf 100644 --- a/ftxui/src/ftxui/dom/inverted.cpp +++ b/ftxui/src/ftxui/dom/inverted.cpp @@ -7,7 +7,7 @@ using ftxui::Screen; class Inverted : public NodeDecorator { public: - Inverted(Children children) : NodeDecorator(std::move(children)) {} + Inverted(Elements children) : NodeDecorator(std::move(children)) {} ~Inverted() override {} void Render(Screen& screen) override { @@ -20,7 +20,7 @@ class Inverted : public NodeDecorator { } }; -std::unique_ptr inverted(Child child) { +std::unique_ptr inverted(Element child) { return std::make_unique(unpack(std::move(child))); } diff --git a/ftxui/src/ftxui/dom/node_decorator.hpp b/ftxui/src/ftxui/dom/node_decorator.hpp index 4b2b5c9..42f4025 100644 --- a/ftxui/src/ftxui/dom/node_decorator.hpp +++ b/ftxui/src/ftxui/dom/node_decorator.hpp @@ -9,7 +9,7 @@ namespace ftxui { // Helper class. class NodeDecorator : public Node { public: - NodeDecorator(Children children) : Node(std::move(children)) {} + NodeDecorator(Elements children) : Node(std::move(children)) {} ~NodeDecorator() override {} void ComputeRequirement() override; void SetBox(Box box) override; diff --git a/ftxui/src/ftxui/dom/underlined.cpp b/ftxui/src/ftxui/dom/underlined.cpp index 9b6e9bb..591232b 100644 --- a/ftxui/src/ftxui/dom/underlined.cpp +++ b/ftxui/src/ftxui/dom/underlined.cpp @@ -7,7 +7,7 @@ using ftxui::Screen; class Underlined : public NodeDecorator { public: - Underlined(Children children) : NodeDecorator(std::move(children)) {} + Underlined(Elements children) : NodeDecorator(std::move(children)) {} ~Underlined() override {} void Render(Screen& screen) override { @@ -20,7 +20,7 @@ class Underlined : public NodeDecorator { } }; -std::unique_ptr underlined(Child child) { +std::unique_ptr underlined(Element child) { return std::make_unique(unpack(std::move(child))); } diff --git a/ftxui/src/ftxui/dom/vbox.cpp b/ftxui/src/ftxui/dom/vbox.cpp index ad8a129..002a63d 100644 --- a/ftxui/src/ftxui/dom/vbox.cpp +++ b/ftxui/src/ftxui/dom/vbox.cpp @@ -5,7 +5,7 @@ namespace ftxui { class VBox : public Node { public: - VBox(Children children) : Node(std::move(children)) {} + VBox(Elements children) : Node(std::move(children)) {} ~VBox() {} void ComputeRequirement() { @@ -59,7 +59,7 @@ class VBox : public Node { } }; -std::unique_ptr vbox(Children children) { +std::unique_ptr vbox(Elements children) { return std::make_unique(std::move(children)); }