Refactor component containers.

This commit is contained in:
Arthur Sonzogni 2019-01-12 18:24:46 +01:00
parent 21644eea6b
commit dba019139b
41 changed files with 293 additions and 423 deletions

View File

@ -1,31 +1,29 @@
#include <chrono>
#include <iostream> #include <iostream>
#include <thread>
#include "ftxui/component/component_vertical.hpp" #include "ftxui/component/container.hpp"
#include "ftxui/component/input.hpp" #include "ftxui/component/input.hpp"
#include "ftxui/component/screen_interactive.hpp" #include "ftxui/component/screen_interactive.hpp"
#include "ftxui/util/string.hpp" #include "ftxui/screen/string.hpp"
using namespace ftxui; using namespace ftxui;
class MyComponent : ComponentVertical { class MyComponent : public Component {
public: public:
MyComponent(Delegate* delegate) MyComponent() {
: ComponentVertical(delegate), Add(&container);
input_1(delegate->NewChild()), container.Add(&input_1);
input_2(delegate->NewChild()), container.Add(&input_2);
input_3(delegate->NewChild()) { container.Add(&input_3);
input_1.placeholder = L"input1"; input_1.placeholder = L"input1";
input_2.placeholder = L"input2"; input_2.placeholder = L"input2";
input_3.placeholder = L"input3"; input_3.placeholder = L"input3";
Focus(&input_1);
} }
std::function<void()> on_enter = []() {}; std::function<void()> on_enter = []() {};
private: private:
Container container = Container::Vertical();
Input input_1; Input input_1;
Input input_2; Input input_2;
Input input_3; Input input_3;
@ -44,7 +42,7 @@ class MyComponent : ComponentVertical {
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
auto screen = ScreenInteractive::TerminalOutput(); auto screen = ScreenInteractive::TerminalOutput();
MyComponent component(screen.delegate()); MyComponent component;
component.on_enter = screen.ExitLoopClosure(); component.on_enter = screen.ExitLoopClosure();
screen.Loop(); screen.Loop(&component);
} }

View File

@ -8,10 +8,13 @@
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;
auto screen = ScreenInteractive::FixedSize(30, 3); auto screen = ScreenInteractive::FixedSize(30, 3);
Menu menu(screen.delegate());
Menu menu;
menu.entries = {L"entry 1", L"entry 2", L"entry 3"}; menu.entries = {L"entry 1", L"entry 2", L"entry 3"};
menu.selected = 0; menu.selected = 0;
menu.on_enter = screen.ExitLoopClosure(); menu.on_enter = screen.ExitLoopClosure();
screen.Loop(); screen.Loop(&menu);
std::cout << "Selected element = " << menu.selected << std::endl;
} }

View File

@ -2,20 +2,20 @@
#include <iostream> #include <iostream>
#include <thread> #include <thread>
#include "ftxui/component/component_horizontal.hpp" #include "ftxui/component/container.hpp"
#include "ftxui/component/component_vertical.hpp"
#include "ftxui/component/menu.hpp" #include "ftxui/component/menu.hpp"
#include "ftxui/component/screen_interactive.hpp" #include "ftxui/component/screen_interactive.hpp"
#include "ftxui/util/string.hpp" #include "ftxui/screen/string.hpp"
using namespace ftxui; using namespace ftxui;
class MyComponent : ComponentHorizontal { class MyComponent : public Component {
public: public:
MyComponent(Delegate* delegate) MyComponent() {
: ComponentHorizontal(delegate), Add(&container);
left_menu(delegate->NewChild()), container.Add(&left_menu);
right_menu(delegate->NewChild()) { container.Add(&right_menu);
left_menu.entries = {L"0%", L"10%", L"20%", L"30%", L"40%", L"50%", left_menu.entries = {L"0%", L"10%", L"20%", L"30%", L"40%", L"50%",
L"60%", L"70%", L"80%", L"90%"}; L"60%", L"70%", L"80%", L"90%"};
right_menu.entries = {L"0%", L"1%", L"2%", L"3%", L"4%", L"5%", 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(); }; left_menu.on_enter = [this]() { on_enter(); };
right_menu.on_enter = [this]() { on_enter(); }; right_menu.on_enter = [this]() { on_enter(); };
Focus(&left_menu);
} }
std::function<void()> on_enter = [](){}; std::function<void()> on_enter = [](){};
private: private:
Container container = Container::Horizontal();
Menu left_menu; Menu left_menu;
Menu right_menu; Menu right_menu;
@ -66,7 +66,7 @@ class MyComponent : ComponentHorizontal {
int main(int argc, const char *argv[]) int main(int argc, const char *argv[])
{ {
auto screen = ScreenInteractive::TerminalOutput(); auto screen = ScreenInteractive::TerminalOutput();
MyComponent component(screen.delegate()); MyComponent component;
component.on_enter = screen.ExitLoopClosure(); component.on_enter = screen.ExitLoopClosure();
screen.Loop(); screen.Loop(&component);
} }

View File

@ -1,25 +1,20 @@
#include <iostream> #include <iostream>
#include <thread> #include <thread>
#include "ftxui/component/component_horizontal.hpp" #include "ftxui/component/container.hpp"
#include "ftxui/component/menu.hpp" #include "ftxui/component/menu.hpp"
#include "ftxui/component/screen_interactive.hpp" #include "ftxui/component/screen_interactive.hpp"
#include "ftxui/util/string.hpp" #include "ftxui/screen/string.hpp"
using namespace ftxui; using namespace ftxui;
class MyComponent : ComponentHorizontal { class MyComponent : public Component {
public: public:
MyComponent(Delegate* delegate) MyComponent() {
: ComponentHorizontal(delegate), Add(&container);
menu_1(delegate->NewChild()),
menu_2(delegate->NewChild()),
menu_3(delegate->NewChild()),
menu_4(delegate->NewChild()),
menu_5(delegate->NewChild()),
menu_6(delegate->NewChild()) {
for(Menu* menu : {&menu_1, &menu_2, &menu_3, &menu_4, &menu_5, &menu_6}) { for(Menu* menu : {&menu_1, &menu_2, &menu_3, &menu_4, &menu_5, &menu_6}) {
container.Add(menu);
menu->entries = { menu->entries = {
L"Monkey", L"Monkey",
L"Dog", L"Dog",
@ -46,12 +41,11 @@ class MyComponent : ComponentHorizontal {
menu_6.normal_style = dim | color(Color::Blue); menu_6.normal_style = dim | color(Color::Blue);
menu_6.selected_style = color(Color::Blue); menu_6.selected_style = color(Color::Blue);
menu_6.active_style = bold | color(Color::Blue); menu_6.active_style = bold | color(Color::Blue);
Focus(&menu_1);
} }
std::function<void()> on_enter = [](){}; std::function<void()> on_enter = [](){};
private: private:
Container container = Container::Horizontal();
Menu menu_1; Menu menu_1;
Menu menu_2; Menu menu_2;
Menu menu_3; Menu menu_3;
@ -75,7 +69,7 @@ class MyComponent : ComponentHorizontal {
int main(int argc, const char *argv[]) int main(int argc, const char *argv[])
{ {
auto screen = ScreenInteractive::TerminalOutput(); auto screen = ScreenInteractive::TerminalOutput();
MyComponent component(screen.delegate()); MyComponent component;
component.on_enter = screen.ExitLoopClosure(); component.on_enter = screen.ExitLoopClosure();
screen.Loop(); screen.Loop(&component);
} }

View File

@ -1,28 +1,28 @@
#include <iostream> #include <iostream>
#include <thread> #include <thread>
#include "ftxui/component/component_vertical.hpp" #include "ftxui/component/container.hpp"
#include "ftxui/component/menu.hpp" #include "ftxui/component/menu.hpp"
#include "ftxui/component/screen_interactive.hpp" #include "ftxui/component/screen_interactive.hpp"
#include "ftxui/component/toggle.hpp" #include "ftxui/component/toggle.hpp"
#include "ftxui/util/string.hpp" #include "ftxui/screen/string.hpp"
using namespace ftxui; using namespace ftxui;
class MyComponent : ComponentVertical { class MyComponent : public Component {
public: public:
MyComponent(Delegate* delegate) MyComponent() {
: ComponentVertical(delegate), Add(&container);
toggle(delegate->NewChild()), container.Add(&toggle);
menu(delegate->NewChild()) { container.Add(&menu);
toggle.options = {L" left ", L" middle ", L" end "}; toggle.options = {L" left ", L" middle ", L" end "};
menu.entries = {L" top ", L" middle ", L" bottom "}; menu.entries = {L" top ", L" middle ", L" bottom "};
Focus(&toggle);
} }
std::function<void()> on_enter = [](){}; std::function<void()> on_enter = [](){};
private: private:
Container container = Container::Vertical();
Toggle toggle; Toggle toggle;
Menu menu; Menu menu;
@ -38,7 +38,7 @@ class MyComponent : ComponentVertical {
int main(int argc, const char *argv[]) int main(int argc, const char *argv[])
{ {
auto screen = ScreenInteractive::TerminalOutput(); auto screen = ScreenInteractive::TerminalOutput();
MyComponent component(screen.delegate()); MyComponent component;
component.on_enter = screen.ExitLoopClosure(); component.on_enter = screen.ExitLoopClosure();
screen.Loop(); screen.Loop(&component);
} }

View File

@ -2,33 +2,32 @@
#include <iostream> #include <iostream>
#include <thread> #include <thread>
#include "ftxui/component/component_horizontal.hpp" #include "ftxui/component/container.hpp"
#include "ftxui/component/component_vertical.hpp"
#include "ftxui/component/screen_interactive.hpp" #include "ftxui/component/screen_interactive.hpp"
#include "ftxui/component/toggle.hpp" #include "ftxui/component/toggle.hpp"
#include "ftxui/util/string.hpp" #include "ftxui/screen/string.hpp"
using namespace ftxui; using namespace ftxui;
class MyComponent : ComponentVertical { class MyComponent : public Component {
public: public:
MyComponent(Delegate* delegate) MyComponent() {
: ComponentVertical(delegate), Add(&container);
toggle_1(delegate->NewChild()), container.Add(&toggle_1);
toggle_2(delegate->NewChild()), container.Add(&toggle_2);
toggle_3(delegate->NewChild()), container.Add(&toggle_3);
toggle_4(delegate->NewChild()) { container.Add(&toggle_4);
toggle_1.options = {L"On", L"Off"}; toggle_1.options = {L"On", L"Off"};
toggle_2.options = {L"Enabled", L"Disabled"}; toggle_2.options = {L"Enabled", L"Disabled"};
toggle_3.options = {L"10€", L"0€"}; toggle_3.options = {L"10€", L"0€"};
toggle_4.options = {L"Nothing", L"One element", L"Several elements"}; toggle_4.options = {L"Nothing", L"One element", L"Several elements"};
Focus(&toggle_1);
} }
std::function<void()> on_enter = []() {}; std::function<void()> on_enter = []() {};
private: private:
Container container = Container::Vertical();
Toggle toggle_1; Toggle toggle_1;
Toggle toggle_2; Toggle toggle_2;
Toggle toggle_3; Toggle toggle_3;
@ -45,23 +44,11 @@ class MyComponent : ComponentVertical {
hbox(text(L" * Number of elements : "), toggle_4.Render()) 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[]) { int main(int argc, const char* argv[]) {
auto screen = ScreenInteractive::TerminalOutput(); auto screen = ScreenInteractive::TerminalOutput();
MyComponent component(screen.delegate()); MyComponent component;
component.on_enter = screen.ExitLoopClosure(); component.on_enter = screen.ExitLoopClosure();
screen.Loop(); screen.Loop(&component);
} }

View File

@ -4,7 +4,7 @@
#include "ftxui/dom/elements.hpp" #include "ftxui/dom/elements.hpp"
#include "ftxui/screen/screen.hpp" #include "ftxui/screen/screen.hpp"
#include "ftxui/util/string.hpp" #include "ftxui/screen/string.hpp"
#include <list> #include <list>
#include <vector> #include <vector>

View File

@ -4,7 +4,7 @@
#include "ftxui/screen/screen.hpp" #include "ftxui/screen/screen.hpp"
#include "ftxui/dom/elements.hpp" #include "ftxui/dom/elements.hpp"
#include "ftxui/util/string.hpp" #include "ftxui/screen/string.hpp"
int main(int argc, const char *argv[]) int main(int argc, const char *argv[])
{ {

View File

@ -4,17 +4,16 @@
#include "ftxui/component/component.hpp" #include "ftxui/component/component.hpp"
#include "ftxui/component/screen_interactive.hpp" #include "ftxui/component/screen_interactive.hpp"
#include "ftxui/util/string.hpp" #include "ftxui/screen/string.hpp"
using namespace ftxui; using namespace ftxui;
class DrawKey : public Component { class DrawKey : public Component {
public: public:
DrawKey(Component::Delegate* delegate) ~DrawKey() override = default;
: Component(delegate) {}
Element Render() override { Element Render() override {
Children children; Elements children;
for (size_t i = std::max(0, (int)keys.size() - 10); i < keys.size(); ++i) { for (size_t i = std::max(0, (int)keys.size() - 10); i < keys.size(); ++i) {
std::string code = ""; std::string code = "";
for (size_t j = 0; j < 5; ++j) for (size_t j = 0; j < 5; ++j)
@ -44,6 +43,6 @@ class DrawKey : public Component {
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
auto screen = ScreenInteractive::FixedSize(80, 10); auto screen = ScreenInteractive::FixedSize(80, 10);
DrawKey draw_key(screen.delegate()); DrawKey draw_key;
screen.Loop(); screen.Loop(&draw_key);
} }

View File

@ -31,9 +31,7 @@ add_library(dom
add_library(component add_library(component
src/ftxui/component/component.cpp src/ftxui/component/component.cpp
src/ftxui/component/component_direction.cpp src/ftxui/component/container.cpp
src/ftxui/component/component_horizontal.cpp
src/ftxui/component/component_vertical.cpp
src/ftxui/component/event.cpp src/ftxui/component/event.cpp
src/ftxui/component/input.cpp src/ftxui/component/input.cpp
src/ftxui/component/menu.cpp src/ftxui/component/menu.cpp

View File

@ -13,50 +13,43 @@ class Focus;
class Component { class Component {
public: 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<Delegate*> children() = 0;
// Navigate in the tree.
virtual Delegate* PreviousSibling() = 0;
virtual Delegate* NextSibling() = 0;
virtual Delegate* Parent() = 0;
virtual Delegate* Root() = 0;
};
// Constructor/Destructor. // Constructor/Destructor.
Component(Delegate* delegate); Component() = default;
virtual ~Component(); virtual ~Component();
// Render the component. // Component hierarchy.
Component* Parent() { return parent_; }
void Add(Component* children);
// Renders the component.
virtual Element Render(); virtual Element Render();
// Handle an event. By default, it calls this function on each children. // Handles an event.
virtual bool OnEvent(Event even); // 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 // Focus management ----------------------------------------------------------
// can be none of them. //
// We say an element has the focus if the chain of GetActiveChild() from the // 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. // root component contains this object.
virtual Component* GetActiveChild() { return nullptr; } virtual Component* ActiveChild();
bool Active(); // True is this component is an active child. // Whether this is the active child of its parent.
bool Focused(); // True if all the ancestors are active childs. bool Active();
// Whether all the ancestors are active.
Component* Parent(); bool Focused();
Component* PreviousSibling();
Component* NextSibling();
private: private:
Delegate* delegate_; Component* parent_ = nullptr;
void Detach();
void Attach(Component* parent);
protected:
std::vector<Component*> children_;
}; };
} // namespace ftxui } // namespace ftxui

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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 */

View File

@ -9,8 +9,8 @@ namespace ftxui {
class Input : public Component { class Input : public Component {
public: public:
// Constructor. // Constructor.
Input(Delegate*); Input() = default;
~Input() override; ~Input() override = default;
// State. // State.
std::wstring content; std::wstring content;

View File

@ -10,7 +10,8 @@ namespace ftxui {
class Menu : public Component { class Menu : public Component {
public: public:
// Constructor. // Constructor.
Menu(Delegate*); Menu() = default;
~Menu() override = default;
// State. // State.
std::vector<std::wstring> entries = {}; std::vector<std::wstring> entries = {};

View File

@ -1,31 +1,25 @@
#ifndef FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP #ifndef FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP
#define FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP #define FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP
#include "ftxui/component/component.hpp"
#include "ftxui/screen/screen.hpp" #include "ftxui/screen/screen.hpp"
#include <functional> #include <functional>
#include <memory> #include <memory>
namespace ftxui { namespace ftxui {
class Component;
class ScreenInteractive : public Screen {
class ScreenInteractive : public ftxui::Screen {
public: public:
static ScreenInteractive FixedSize(size_t dimx, size_t dimy); static ScreenInteractive FixedSize(size_t dimx, size_t dimy);
static ScreenInteractive Fullscreen(); static ScreenInteractive Fullscreen();
static ScreenInteractive TerminalOutput(); static ScreenInteractive TerminalOutput();
~ScreenInteractive(); ~ScreenInteractive();
void Loop(); void Loop(Component*);
std::function<void()> ExitLoopClosure(); std::function<void()> ExitLoopClosure();
Component::Delegate* delegate();
private: private:
class Delegate; void Draw(Component* component);
std::unique_ptr<Delegate> delegate_;
void PrepareDraw();
bool quit_ = false; bool quit_ = false;
enum class Dimension { enum class Dimension {
@ -34,7 +28,6 @@ class ScreenInteractive : public ftxui::Screen {
Fullscreen, Fullscreen,
}; };
Dimension dimension_ = Dimension::Fixed; Dimension dimension_ = Dimension::Fixed;
ScreenInteractive(size_t dimx, size_t dimy, Dimension dimension); ScreenInteractive(size_t dimx, size_t dimy, Dimension dimension);
}; };

View File

@ -10,7 +10,7 @@ namespace ftxui {
class Toggle : public Component { class Toggle : public Component {
public: public:
// Constructor. // Constructor.
Toggle(Delegate*); ~Toggle() override = default;
// State. // State.
size_t activated = 0; size_t activated = 0;

View File

@ -9,15 +9,13 @@
namespace ftxui { namespace ftxui {
using Element = std::unique_ptr<Node>; using Element = std::unique_ptr<Node>;
using Elements = std::vector<Element>;
using Decorator = std::function<Element(Element)>; using Decorator = std::function<Element(Element)>;
using Child = std::unique_ptr<Node>;
using Children = std::vector<Child>;
using Color = ftxui::Color;
// --- Layout ---- // --- Layout ----
Element vbox(Children); Element vbox(Elements);
Element hbox(Children); Element hbox(Elements);
Element dbox(Children); Element dbox(Elements);
// -- Flexibility -- // -- Flexibility --
Element filler(); Element filler();
@ -29,7 +27,7 @@ Element text(std::wstring text);
Element separator(); Element separator();
Element gauge(float ratio); Element gauge(float ratio);
Element frame(Element); Element frame(Element);
Element window(Child title, Child content); Element window(Element title, Element content);
Element spinner(int charset_index, size_t image_index); Element spinner(int charset_index, size_t image_index);
// -- Decorator --- // -- Decorator ---

View File

@ -2,7 +2,7 @@
// Turn a set of arguments into a vector. // Turn a set of arguments into a vector.
template <class... Args> template <class... Args>
Children unpack(Args... args) { Elements unpack(Args... args) {
using T = std::common_type_t<Args...>; using T = std::common_type_t<Args...>;
std::vector<T> vec; std::vector<T> vec;
(vec.push_back(std::forward<Args>(args)), ...); (vec.push_back(std::forward<Args>(args)), ...);

View File

@ -1,57 +1,53 @@
#include "ftxui/component/component.hpp" #include "ftxui/component/component.hpp"
#include "ftxui/component/delegate.hpp"
#include <assert.h> #include <assert.h>
namespace ftxui { 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() { void Component::Add(Component* child) {
using namespace ftxui; child->Attach(this);
return text(L"Not implemented component"); }
Component::~Component() {
Detach();
} }
bool Component::OnEvent(Event event) { bool Component::OnEvent(Event event) {
return false; for(Component* child : children_) {
} if (child->OnEvent(event))
bool Component::Focused() {
Delegate* current = delegate_->Root();
while (current) {
if (current == delegate_)
return true; return true;
Component* active_child = current->component()->GetActiveChild();
current = active_child ? active_child->delegate_ : nullptr;
} }
return false; return false;
} }
bool Component::Active() { Component* Component::ActiveChild() {
Delegate* parent = delegate_->Parent(); return children_.empty() ? nullptr : children_.front();
return parent && parent->component()->GetActiveChild() == this;
} }
Component* Component::PreviousSibling() { Element Component::Render() {
Delegate* sibling = delegate_->PreviousSibling(); return text(L"Not implemented component");
return sibling ? sibling->component() : nullptr;
} }
Component* Component::NextSibling() { bool Component::Focused() {
Delegate* sibling = delegate_->NextSibling(); Component* current = this;
return sibling ? sibling->component() : nullptr; for(;;) {
} Component* parent = current->parent_;
if (!parent)
Component* Component::Parent() { return true;
Delegate* parent_delegate = delegate_->Parent(); if (parent->ActiveChild() != current)
if (!parent_delegate) return false;
return nullptr; current = parent;
return parent_delegate->component(); }
} }
} // namespace ftxui } // namespace ftxui

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,11 +1,8 @@
#include "ftxui/component/input.hpp" #include "ftxui/component/input.hpp"
#include "ftxui/util/string.hpp" #include "ftxui/screen/string.hpp"
namespace ftxui { namespace ftxui {
Input::Input(Delegate* delegate): Component(delegate) {}
Input::~Input() {}
// Component implementation. // Component implementation.
Element Input::Render() { Element Input::Render() {
bool is_focused = Focused(); bool is_focused = Focused();

View File

@ -4,8 +4,6 @@
namespace ftxui { namespace ftxui {
Menu::Menu(Delegate* delegate) : Component(delegate) {}
Element Menu::Render() { Element Menu::Render() {
std::vector<Element> elements; std::vector<Element> elements;
bool focused = Focused(); bool focused = Focused();

View File

@ -45,53 +45,10 @@ Event GetEvent() {
}; // namespace }; // namespace
class ScreenInteractive::Delegate : public Component::Delegate {
public:
Delegate() : root_(this) {}
void Register(Component* c) override { component_ = c; }
std::vector<std::unique_ptr<Delegate>> 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<Component::Delegate*> children() override {
std::vector<Component::Delegate*> 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, ScreenInteractive::ScreenInteractive(size_t dimx,
size_t dimy, size_t dimy,
Dimension dimension) Dimension dimension)
: Screen(dimx, dimy), delegate_(new Delegate), dimension_(dimension) {} : Screen(dimx, dimy), dimension_(dimension) {}
ScreenInteractive::~ScreenInteractive() {} ScreenInteractive::~ScreenInteractive() {}
// static // static
@ -109,10 +66,10 @@ ScreenInteractive ScreenInteractive::TerminalOutput() {
return ScreenInteractive(0, 0, Dimension::TerminalOutput); return ScreenInteractive(0, 0, Dimension::TerminalOutput);
} }
void ScreenInteractive::Loop() { void ScreenInteractive::Loop(Component* component) {
std::cout << "\033[?9h"; /* Send Mouse Row & Column on Button Press */ //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 << "\033[?1000h"; [> Send Mouse X & Y on button press and release <]
std::cout << std::flush; //std::cout << std::flush;
// Save the old terminal configuration. // Save the old terminal configuration.
struct termios terminal_configuration_old; struct termios terminal_configuration_old;
@ -130,23 +87,27 @@ void ScreenInteractive::Loop() {
std::string reset_position; std::string reset_position;
while (!quit_) { while (!quit_) {
PrepareDraw(); Draw(component);
std::cout << reset_position << ToString() << std::flush; std::cout << reset_position << ToString() << std::flush;
reset_position = ResetPosition(); reset_position = ResetPosition();
Clear(); Clear();
delegate_->OnEvent(GetEvent()); component->OnEvent(GetEvent());
} }
// Restore the old terminal configuration. // Restore the old terminal configuration.
tcsetattr(STDIN_FILENO, TCSANOW, &terminal_configuration_old); tcsetattr(STDIN_FILENO, TCSANOW, &terminal_configuration_old);
std::cout << std::endl;
} }
void ScreenInteractive::PrepareDraw() { void ScreenInteractive::Draw(Component* component) {
auto document = delegate_->component()->Render(); auto document = component->Render();
size_t dimx; size_t dimx;
size_t dimy; size_t dimy;
switch (dimension_) { switch (dimension_) {
case Dimension::Fixed: case Dimension::Fixed:
dimx = dimx_;
dimy = dimy_;
break; break;
case Dimension::TerminalOutput: case Dimension::TerminalOutput:
document->ComputeRequirement(); document->ComputeRequirement();
@ -161,8 +122,10 @@ void ScreenInteractive::PrepareDraw() {
} }
if (dimx != dimx_ || dimy != dimy_) { if (dimx != dimx_ || dimy != dimy_) {
std::cerr << dimx_ << " " << dimy_ << std::endl;
dimx_ = dimx; dimx_ = dimx;
dimy_ = dimy; dimy_ = dimy;
std::cerr << dimx_ << " " << dimy_ << std::endl;
pixels_ = std::vector<std::vector<Pixel>>( pixels_ = std::vector<std::vector<Pixel>>(
dimy, std::vector<Pixel>(dimx)); dimy, std::vector<Pixel>(dimx));
} }
@ -170,10 +133,6 @@ void ScreenInteractive::PrepareDraw() {
Render(*this, document.get()); Render(*this, document.get());
} }
Component::Delegate* ScreenInteractive::delegate() {
return delegate_.get();
}
std::function<void()> ScreenInteractive::ExitLoopClosure() { std::function<void()> ScreenInteractive::ExitLoopClosure() {
return [this]() { quit_ = true; }; return [this]() { quit_ = true; };
} }

View File

@ -2,13 +2,10 @@
namespace ftxui { namespace ftxui {
Toggle::Toggle(Delegate* delegate) : Component(delegate) {}
Element Toggle::Render() { Element Toggle::Render() {
auto highlight = Focused() ? inverted : bold; auto highlight = Focused() ? inverted : bold;
Children children; Elements children;
for(size_t i = 0; i<options.size(); ++i) { for(size_t i = 0; i<options.size(); ++i) {
// Separator. // Separator.
if (i != 0) if (i != 0)

View File

@ -5,7 +5,7 @@ namespace ftxui {
class Blink : public NodeDecorator { class Blink : public NodeDecorator {
public: public:
Blink(Children children) : NodeDecorator(std::move(children)) {} Blink(Elements children) : NodeDecorator(std::move(children)) {}
~Blink() override {} ~Blink() override {}
void Render(Screen& screen) override { void Render(Screen& screen) override {
@ -18,7 +18,7 @@ class Blink : public NodeDecorator {
} }
}; };
std::unique_ptr<Node> blink(Child child) { std::unique_ptr<Node> blink(Element child) {
return std::make_unique<Blink>(unpack(std::move(child))); return std::make_unique<Blink>(unpack(std::move(child)));
} }

View File

@ -5,7 +5,7 @@ namespace ftxui {
class Bold : public NodeDecorator { class Bold : public NodeDecorator {
public: public:
Bold(Children children) : NodeDecorator(std::move(children)) {} Bold(Elements children) : NodeDecorator(std::move(children)) {}
~Bold() override {} ~Bold() override {}
void Render(Screen& screen) override { void Render(Screen& screen) override {
@ -18,7 +18,7 @@ class Bold : public NodeDecorator {
} }
}; };
std::unique_ptr<Node> bold(Child child) { std::unique_ptr<Node> bold(Element child) {
return std::make_unique<Bold>(unpack(std::move(child))); return std::make_unique<Bold>(unpack(std::move(child)));
} }

View File

@ -5,7 +5,7 @@ namespace ftxui {
class BgColor : public NodeDecorator { class BgColor : public NodeDecorator {
public: public:
BgColor(Children children, Color color) BgColor(Elements children, Color color)
: NodeDecorator(std::move(children)), color_(color) {} : NodeDecorator(std::move(children)), color_(color) {}
void Render(Screen& screen) override { void Render(Screen& screen) override {
@ -22,7 +22,7 @@ class BgColor : public NodeDecorator {
class FgColor : public NodeDecorator { class FgColor : public NodeDecorator {
public: public:
FgColor(Children children, Color color) FgColor(Elements children, Color color)
: NodeDecorator(std::move(children)), color_(color) {} : NodeDecorator(std::move(children)), color_(color) {}
~FgColor() override {} ~FgColor() override {}
@ -38,22 +38,22 @@ class FgColor : public NodeDecorator {
Color color_; Color color_;
}; };
std::unique_ptr<Node> color(Color c, Child child) { std::unique_ptr<Node> color(Color c, Element child) {
return std::make_unique<FgColor>(unpack(std::move(child)), c); return std::make_unique<FgColor>(unpack(std::move(child)), c);
} }
std::unique_ptr<Node> bgcolor(Color c, Child child) { std::unique_ptr<Node> bgcolor(Color c, Element child) {
return std::make_unique<BgColor>(unpack(std::move(child)), c); return std::make_unique<BgColor>(unpack(std::move(child)), c);
} }
Decorator color(Color c) { Decorator color(Color c) {
return [c](Child child) { return [c](Element child) {
return color(c, std::move(child)); return color(c, std::move(child));
}; };
} }
Decorator bgcolor(Color c) { Decorator bgcolor(Color c) {
return [c](Child child) { return [c](Element child) {
return bgcolor(c, std::move(child)); return bgcolor(c, std::move(child));
}; };
} }

View File

@ -5,7 +5,7 @@ namespace ftxui {
class DBox : public Node { class DBox : public Node {
public: public:
DBox(Children children) : Node(std::move(children)) {} DBox(Elements children) : Node(std::move(children)) {}
~DBox() {} ~DBox() {}
void ComputeRequirement() override { void ComputeRequirement() override {
@ -28,7 +28,7 @@ class DBox : public Node {
} }
}; };
std::unique_ptr<Node> dbox(Children children) { std::unique_ptr<Node> dbox(Elements children) {
return std::make_unique<DBox>(std::move(children)); return std::make_unique<DBox>(std::move(children));
} }

View File

@ -7,7 +7,7 @@ using ftxui::Screen;
class Dim : public NodeDecorator { class Dim : public NodeDecorator {
public: public:
Dim(Children children) : NodeDecorator(std::move(children)) {} Dim(Elements children) : NodeDecorator(std::move(children)) {}
~Dim() override {} ~Dim() override {}
void Render(Screen& screen) override { void Render(Screen& screen) override {
@ -20,7 +20,7 @@ class Dim : public NodeDecorator {
} }
}; };
std::unique_ptr<Node> dim(Child child) { std::unique_ptr<Node> dim(Element child) {
return std::make_unique<Dim>(unpack(std::move(child))); return std::make_unique<Dim>(unpack(std::move(child)));
} }

View File

@ -9,7 +9,7 @@ static wchar_t charset[] = L"┌┐└┘─│┬┴┤├";
class Frame : public Node { class Frame : public Node {
public: public:
Frame(Children children) : Node(std::move(children)) {} Frame(Elements children) : Node(std::move(children)) {}
~Frame() override {} ~Frame() override {}
void ComputeRequirement() override { void ComputeRequirement() override {
@ -81,16 +81,16 @@ class Frame : public Node {
} }
}; };
std::unique_ptr<Node> frame(Child child) { std::unique_ptr<Node> frame(Element child) {
return std::make_unique<Frame>(unpack(std::move(child))); return std::make_unique<Frame>(unpack(std::move(child)));
} }
std::unique_ptr<Node> window(Child title, Child content) { std::unique_ptr<Node> window(Element title, Element content) {
return std::make_unique<Frame>(unpack(std::move(content), std::move(title))); return std::make_unique<Frame>(unpack(std::move(content), std::move(title)));
} }
Decorator boxed() { Decorator boxed() {
return [](Child child) { return [](Element child) {
return frame(std::move(child)); return frame(std::move(child));
}; };
} }

View File

@ -5,7 +5,7 @@ namespace ftxui {
class HBox : public Node { class HBox : public Node {
public: public:
HBox(Children children) : Node(std::move(children)) {} HBox(Elements children) : Node(std::move(children)) {}
~HBox() {} ~HBox() {}
void ComputeRequirement() override { void ComputeRequirement() override {
@ -59,7 +59,7 @@ class HBox : public Node {
} }
}; };
std::unique_ptr<Node> hbox(Children children) { std::unique_ptr<Node> hbox(Elements children) {
return std::make_unique<HBox>(std::move(children)); return std::make_unique<HBox>(std::move(children));
} }

View File

@ -7,7 +7,7 @@ using ftxui::Screen;
class Inverted : public NodeDecorator { class Inverted : public NodeDecorator {
public: public:
Inverted(Children children) : NodeDecorator(std::move(children)) {} Inverted(Elements children) : NodeDecorator(std::move(children)) {}
~Inverted() override {} ~Inverted() override {}
void Render(Screen& screen) override { void Render(Screen& screen) override {
@ -20,7 +20,7 @@ class Inverted : public NodeDecorator {
} }
}; };
std::unique_ptr<Node> inverted(Child child) { std::unique_ptr<Node> inverted(Element child) {
return std::make_unique<Inverted>(unpack(std::move(child))); return std::make_unique<Inverted>(unpack(std::move(child)));
} }

View File

@ -9,7 +9,7 @@ namespace ftxui {
// Helper class. // Helper class.
class NodeDecorator : public Node { class NodeDecorator : public Node {
public: public:
NodeDecorator(Children children) : Node(std::move(children)) {} NodeDecorator(Elements children) : Node(std::move(children)) {}
~NodeDecorator() override {} ~NodeDecorator() override {}
void ComputeRequirement() override; void ComputeRequirement() override;
void SetBox(Box box) override; void SetBox(Box box) override;

View File

@ -7,7 +7,7 @@ using ftxui::Screen;
class Underlined : public NodeDecorator { class Underlined : public NodeDecorator {
public: public:
Underlined(Children children) : NodeDecorator(std::move(children)) {} Underlined(Elements children) : NodeDecorator(std::move(children)) {}
~Underlined() override {} ~Underlined() override {}
void Render(Screen& screen) override { void Render(Screen& screen) override {
@ -20,7 +20,7 @@ class Underlined : public NodeDecorator {
} }
}; };
std::unique_ptr<Node> underlined(Child child) { std::unique_ptr<Node> underlined(Element child) {
return std::make_unique<Underlined>(unpack(std::move(child))); return std::make_unique<Underlined>(unpack(std::move(child)));
} }

View File

@ -5,7 +5,7 @@ namespace ftxui {
class VBox : public Node { class VBox : public Node {
public: public:
VBox(Children children) : Node(std::move(children)) {} VBox(Elements children) : Node(std::move(children)) {}
~VBox() {} ~VBox() {}
void ComputeRequirement() { void ComputeRequirement() {
@ -59,7 +59,7 @@ class VBox : public Node {
} }
}; };
std::unique_ptr<Node> vbox(Children children) { std::unique_ptr<Node> vbox(Elements children) {
return std::make_unique<VBox>(std::move(children)); return std::make_unique<VBox>(std::move(children));
} }