Add the Renderer component.

This commit is contained in:
ArthurSonzogni 2021-05-13 11:44:47 +02:00
parent 6d75cb2748
commit c9aa1805eb
No known key found for this signature in database
GPG Key ID: 41D98248C074CD6C
9 changed files with 400 additions and 324 deletions

View File

@ -99,6 +99,7 @@ add_library(component
src/ftxui/component/menu.cpp
src/ftxui/component/radiobox.cpp
src/ftxui/component/radiobox.cpp
src/ftxui/component/renderer.cpp
src/ftxui/component/screen_interactive.cpp
src/ftxui/component/slider.cpp
src/ftxui/component/terminal_input_parser.cpp

View File

@ -1,43 +1,36 @@
#include <string> // for operator+, to_wstring, allocator, wstring
#include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Button, Make
#include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/container.hpp" // for Container
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive
#include "ftxui/dom/elements.hpp" // for separator, Element, gauge, text, operator|, vbox, border
using namespace ftxui;
class MyComponent : public ComponentBase {
private:
std::wstring label_add = L"Increase";
std::wstring label_rm = L"Decrease";
int value_ = 50;
int main(int argc, const char* argv[]) {
int value = 50;
std::wstring label_dec = L"decrease";
std::wstring label_inc = L"increase";
public:
MyComponent() {
Add(Container::Horizontal({
Button(&label_rm, [&] { value_--; }),
Button(&label_add, [&] { value_++; }),
}));
}
// The tree of components. This defines how to navigate using the keyboard.
auto buttons = Container::Horizontal({
Button(&label_dec, [&] { value--; }),
Button(&label_inc, [&] { value++; }),
});
Element Render() override {
// Modify the way to render them on screen:
auto component = Renderer(buttons, [&] {
return vbox({
text(L"Value = " + std::to_wstring(value_)),
text(L"value = " + std::to_wstring(value)),
separator(),
gauge(value_ * 0.01f),
gauge(value * 0.01f),
separator(),
ComponentBase::Render(),
buttons->Render(),
}) |
border;
}
};
});
int main(int argc, const char* argv[]) {
auto screen = ScreenInteractive::FitComponent();
screen.Loop(Make<MyComponent>());
screen.Loop(component);
return 0;
}

View File

@ -6,8 +6,7 @@
using namespace ftxui;
class MyComponent : public ComponentBase {
private:
int main(int argc, const char* argv[]) {
std::wstring build_examples_label = L"Build examples";
std::wstring build_tests_label = L"Build tests";
std::wstring use_webassembly_label = L"Use WebAssembly";
@ -16,19 +15,14 @@ class MyComponent : public ComponentBase {
bool build_tests_state = false;
bool use_webassembly_state = true;
Component container = Container::Vertical({
auto component = Container::Vertical({
Checkbox(&build_examples_label, &build_examples_state),
Checkbox(&build_tests_label, &build_tests_state),
Checkbox(&use_webassembly_label, &use_webassembly_state),
});
public:
MyComponent() { Add(container); }
};
int main(int argc, const char* argv[]) {
auto screen = ScreenInteractive::TerminalOutput();
screen.Loop(Make<MyComponent>());
screen.Loop(component);
return 0;
}

View File

@ -1,9 +1,7 @@
#include <ext/alloc_traits.h> // for __alloc_traits<>::value_type
#include <memory> // for unique_ptr, make_unique, __shared_ptr_access
#include <string> // for operator+, wstring
#include <vector> // for vector
#include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Checkbox, Make
#include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/container.hpp" // for Container
@ -13,49 +11,28 @@
using namespace ftxui;
struct CheckboxAndState {
struct CheckboxState {
std::wstring label;
bool state;
Component component;
};
std::unique_ptr<CheckboxAndState> MakeCheckbox(std::wstring label) {
auto out = std::make_unique<CheckboxAndState>();
out->label = label;
out->state = false;
out->component = Checkbox(&out->label, &out->state);
return out;
}
class MyComponent : public ComponentBase {
public:
MyComponent() {
Add(container);
checkbox.resize(30);
for (int i = 0; i < checkbox.size(); ++i) {
checkbox[i] = MakeCheckbox(L"CheckBox " + to_wstring(i));
container->Add(checkbox[i]->component);
}
}
// clang-format off
Element Render() override {
Elements content;
return vbox(container->Render())
| frame
| size(HEIGHT, LESS_THAN, 10)
| border;
}
private:
std::vector<std::unique_ptr<CheckboxAndState>> checkbox;
Component container = Container::Vertical();
bool checked;
};
int main(int argc, const char* argv[]) {
int size = 30;
std::vector<CheckboxState> states(size);
auto container = Container::Vertical({});
for(int i = 0; i<size; ++i) {
states[i].checked = false;
states[i].label = L"Checkbox " + to_wstring(i);
container->Add(Checkbox(&states[i].label, &states[i].checked));
}
auto component = Renderer(container, [&] {
return container->Render() | frame | ftxui::size(HEIGHT, LESS_THAN, 10) |
border;
});
auto screen = ScreenInteractive::FitComponent();
auto my_component = Make<MyComponent>();
screen.Loop(my_component);
screen.Loop(component);
return 0;
}

View File

@ -12,111 +12,117 @@
using namespace ftxui;
class MyComponent : public ComponentBase {
const std::vector<std::wstring> menu_entries_ = {
// Display a component nicely with a title on the left.
Component Wrap(std::wstring name, Component component) {
return Renderer(component, [name, component] {
return hbox({
text(name) | size(WIDTH, EQUAL, 8),
separator(),
component->Render() | xflex,
}) |
xflex;
});
}
int main(int argc, const char* argv[]) {
auto screen = ScreenInteractive::FitComponent();
// -- Menu ----------------------------------------------------------------------
const std::vector<std::wstring> menu_entries = {
L"Menu 1",
L"Menu 2",
L"Menu 3",
L"Menu 4",
};
int menu_selected_ = 0;
Component menu_ = Menu(&menu_entries_, &menu_selected_);
int menu_selected = 0;
auto menu = Menu(&menu_entries, &menu_selected);
menu = Wrap(L"Menu", menu);
int toggle_selected_ = 0;
std::vector<std::wstring> toggle_entries_ = {
// -- Toggle------------------------------------------------------------------
int toggle_selected = 0;
std::vector<std::wstring> toggle_entries = {
L"Toggle_1",
L"Toggle_2",
};
Component toggle_ = Toggle(&toggle_entries_, &toggle_selected_);
auto toggle = Toggle(&toggle_entries, &toggle_selected);
toggle = Wrap(L"Toggle", toggle);
std::wstring checkbox_1_label_ = L"checkbox1";
std::wstring checkbox_2_label_ = L"checkbox2";
bool checkbox_1_selected_ = false;
bool checkbox_2_selected_ = false;
// -- Checkbox ---------------------------------------------------------------
std::wstring checkbox_1_label = L"checkbox1";
std::wstring checkbox_2_label = L"checkbox2";
bool checkbox_1_selected = false;
bool checkbox_2_selected = false;
Component checkbox_container_ = Container::Vertical({
Checkbox(&checkbox_1_label_, &checkbox_1_selected_),
Checkbox(&checkbox_2_label_, &checkbox_2_selected_),
auto checkboxes = Container::Vertical({
Checkbox(&checkbox_1_label, &checkbox_1_selected),
Checkbox(&checkbox_2_label, &checkbox_2_selected),
});
checkboxes = Wrap(L"Checkbox", checkboxes);
int radiobox_selected_ = 0;
std::vector<std::wstring> radiobox_entries_ = {
// -- Radiobox ---------------------------------------------------------------
int radiobox_selected = 0;
std::vector<std::wstring> radiobox_entries = {
L"Radiobox 1",
L"Radiobox 2",
L"Radiobox 3",
L"Radiobox 4",
};
Component radiobox_ = Radiobox(&radiobox_entries_, &radiobox_selected_);
auto radiobox = Radiobox(&radiobox_entries, &radiobox_selected);
radiobox = Wrap(L"Radiobox", radiobox);
std::wstring input_label_;
std::wstring input_placeholder_ = L"input";
Component input_ = Input(&input_label_, &input_placeholder_);
// -- Input ------------------------------------------------------------------
std::wstring input_label;
std::wstring input_placeholder = L"input";
auto input = Input(&input_label, &input_placeholder);
input = Wrap(L"Input", input);
std::wstring button_label_ = L"Quit";
// -- Button -----------------------------------------------------------------
std::wstring button_label = L"Quit";
std::function<void()> on_button_clicked_;
Component button_ = Button(&button_label_, [this] { on_button_clicked_(); });
auto button = Button(&button_label, screen.ExitLoopClosure());
button = Wrap(L"Button", button);
int slider_value_1_ = 12;
int slider_value_2_ = 56;
int slider_value_3_ = 128;
Component slider_container_ = Container::Vertical({
Slider(L"R:", &slider_value_1_, 0, 256, 1),
Slider(L"G:", &slider_value_2_, 0, 256, 1),
Slider(L"B:", &slider_value_3_, 0, 256, 1),
// -- Slider -----------------------------------------------------------------
int slider_value_1 = 12;
int slider_value_2 = 56;
int slider_value_3 = 128;
auto sliders = Container::Vertical({
Slider(L"R:", &slider_value_1, 0, 256, 1),
Slider(L"G:", &slider_value_2, 0, 256, 1),
Slider(L"B:", &slider_value_3, 0, 256, 1),
});
sliders = Wrap(L"Slider", sliders);
// -- Layout -----------------------------------------------------------------
auto layout = Container::Vertical({
menu,
toggle,
checkboxes,
radiobox,
input,
sliders,
button,
});
public:
MyComponent(std::function<void(void)> on_quit) : on_quit_(on_quit) {
Add(Container::Vertical({
menu_,
toggle_,
checkbox_container_,
radiobox_,
input_,
slider_container_,
button_,
}));
}
Element Render(std::wstring name, Element element) {
return hbox({
text(name) | size(WIDTH, EQUAL, 8),
auto component = Renderer(layout, [&] {
return vbox({
menu->Render(),
separator(),
element | xflex,
}) |
xflex;
}
Element Render(std::wstring name, Component& component) {
return Render(name, component->Render());
}
Element Render() override {
return //
vbox({
Render(L"menu", menu_),
toggle->Render(),
separator(),
Render(L"toggle", toggle_),
checkboxes->Render(),
separator(),
Render(L"checkbox", checkbox_container_),
radiobox->Render(),
separator(),
Render(L"radiobox", radiobox_),
input->Render(),
separator(),
Render(L"input", input_) | size(WIDTH, LESS_THAN, 50),
sliders->Render(),
separator(),
Render(L"slider", slider_container_),
separator(),
Render(L"button", button_),
button->Render(),
}) |
xflex | size(WIDTH, GREATER_THAN, 40) | border;
}
});
std::function<void()> on_quit_;
};
int main(int argc, const char* argv[]) {
auto screen = ScreenInteractive::FitComponent();
auto component = Make<MyComponent>(screen.ExitLoopClosure());
screen.Loop(component);
return 0;

View File

@ -20,32 +20,32 @@
using namespace ftxui;
int shift = 0;
class Graph {
int main(int argc, const char* argv[]) {
auto screen = ScreenInteractive::Fullscreen();
int shift = 0;
class Graph {
public:
Graph(int* shift) : shift_(shift) {}
std::vector<int> operator()(int width, int height) {
std::vector<int> output(width);
for (int i = 0; i < width; ++i) {
float v = 0;
v += 0.1f * sin((i + shift) * 0.1f);
v += 0.2f * sin((i + shift + 10) * 0.15f);
v += 0.1f * sin((i + shift) * 0.03f);
v += 0.1f * sin((i + *shift_) * 0.1f);
v += 0.2f * sin((i + *shift_ + 10) * 0.15f);
v += 0.1f * sin((i + *shift_) * 0.03f);
v *= height;
v += 0.5f * height;
output[i] = (int)v;
}
return output;
}
};
int* shift_;
};
class HTopComponent : public ComponentBase {
Graph my_graph;
public:
HTopComponent() {}
~HTopComponent() override {}
Element Render() override {
Graph my_graph(&shift);
auto htop = Renderer([&] {
auto frequency = vbox({
text(L"Frequency [Mhz]") | hcenter,
hbox({
@ -98,10 +98,9 @@ class HTopComponent : public ComponentBase {
ram | flex,
}) |
flex | border;
}
};
});
const std::vector<std::wstring> compiler_entries = {
const std::vector<std::wstring> compiler_entries = {
L"gcc",
L"clang",
L"emcc",
@ -141,9 +140,8 @@ const std::vector<std::wstring> compiler_entries = {
L"VMS Interpreters",
L"Rexx Interpreters",
L"CLI compilers",
};
};
class CompilerComponent : public ComponentBase {
int compiler_selected = 0;
Component compiler = Radiobox(&compiler_entries, &compiler_selected);
@ -178,10 +176,7 @@ class CompilerComponent : public ComponentBase {
Checkbox(&options_label[3], &options_state[3]),
});
public:
~CompilerComponent() override {}
CompilerComponent() {
Add(Container::Horizontal({
auto compiler_component = Container::Horizontal({
compiler,
flags,
Container::Vertical({
@ -191,15 +186,38 @@ class CompilerComponent : public ComponentBase {
input,
}),
}),
}));
});
InputBase::From(input_add)->on_enter = [this] {
InputBase::From(input_add)->on_enter = [&] {
input_entries.push_back(input_add_content);
input_add_content = L"";
};
}
Element Render() override {
auto render_command = [&] {
Elements line;
// Compiler
line.push_back(text(compiler_entries[compiler_selected]) | bold);
// flags
for (int i = 0; i < 4; ++i) {
if (options_state[i]) {
line.push_back(text(L" "));
line.push_back(text(options_label[i]) | dim);
}
}
// Executable
if (!executable_content_.empty()) {
line.push_back(text(L" -O ") | bold);
line.push_back(text(executable_content_) | color(Color::BlueLight) |
bold);
}
// Input
for (auto& it : input_entries) {
line.push_back(text(L" " + it) | color(Color::RedLight));
}
return line;
};
auto compiler_renderer = Renderer(compiler_component, [&] {
auto compiler_win = window(text(L"Compiler"), compiler->Render() | frame);
auto flags_win = window(text(L"Flags"), flags->Render());
auto executable_win = window(text(L"Executable:"), executable_->Render());
@ -227,50 +245,21 @@ class CompilerComponent : public ComponentBase {
}),
filler(),
}),
hflow(RenderCommandLine()) | flex_grow,
hflow(render_command()) | flex_grow,
}) |
flex_grow | border;
}
});
Elements RenderCommandLine() {
Elements line;
// Compiler
line.push_back(text(compiler_entries[compiler_selected]) | bold);
// flags
for (int i = 0; i < 4; ++i) {
if (options_state[i]) {
line.push_back(text(L" "));
line.push_back(text(options_label[i]) | dim);
}
}
// Executable
if (!executable_content_.empty()) {
line.push_back(text(L" -O ") | bold);
line.push_back(text(executable_content_) | color(Color::BlueLight) |
bold);
}
// Input
for (auto& it : input_entries) {
line.push_back(text(L" " + it) | color(Color::RedLight));
}
return line;
}
};
class SpinnerComponent : public ComponentBase {
Element Render() override {
auto spinner_tab_renderer = Renderer([&] {
Elements entries;
for (int i = 0; i < 22; ++i) {
if (i != 0)
entries.push_back(spinner(i, shift / 2) | bold |
size(WIDTH, GREATER_THAN, 2) | border);
}
return hflow(std::move(entries)) | border;
}
};
});
class ColorComponent : public ComponentBase {
Element Render() override {
auto color_tab_renderer = Renderer([] {
return hbox({
vbox({
color(Color::Default, text(L"Default")),
@ -312,79 +301,67 @@ class ColorComponent : public ComponentBase {
}),
}) |
hcenter | border;
}
};
});
class GaugeComponent : public ComponentBase {
Element RenderGauge(int delta) {
auto render_gauge = [&shift](int delta) {
float progress = (shift + delta) % 1000 / 1000.f;
return hbox({
text(std::to_wstring(int(progress * 100)) + L"% ") |
size(WIDTH, EQUAL, 5),
gauge(progress),
});
}
Element Render() override {
};
auto gauge_component = Renderer([render_gauge] {
return vbox({
RenderGauge(0) | color(Color::Black),
RenderGauge(100) | color(Color::GrayDark),
RenderGauge(50) | color(Color::GrayLight),
RenderGauge(6894) | color(Color::White),
render_gauge(0) | color(Color::Black),
render_gauge(100) | color(Color::GrayDark),
render_gauge(50) | color(Color::GrayLight),
render_gauge(6894) | color(Color::White),
separator(),
RenderGauge(6841) | color(Color::Blue),
RenderGauge(9813) | color(Color::BlueLight),
RenderGauge(98765) | color(Color::Cyan),
RenderGauge(98) | color(Color::CyanLight),
RenderGauge(9846) | color(Color::Green),
RenderGauge(1122) | color(Color::GreenLight),
RenderGauge(84) | color(Color::Magenta),
RenderGauge(645) | color(Color::MagentaLight),
RenderGauge(568) | color(Color::Red),
RenderGauge(2222) | color(Color::RedLight),
RenderGauge(220) | color(Color::Yellow),
RenderGauge(348) | color(Color::YellowLight),
render_gauge(6841) | color(Color::Blue),
render_gauge(9813) | color(Color::BlueLight),
render_gauge(98765) | color(Color::Cyan),
render_gauge(98) | color(Color::CyanLight),
render_gauge(9846) | color(Color::Green),
render_gauge(1122) | color(Color::GreenLight),
render_gauge(84) | color(Color::Magenta),
render_gauge(645) | color(Color::MagentaLight),
render_gauge(568) | color(Color::Red),
render_gauge(2222) | color(Color::RedLight),
render_gauge(220) | color(Color::Yellow),
render_gauge(348) | color(Color::YellowLight),
}) |
border;
};
};
});
class Tab : public ComponentBase {
public:
int tab_index = 0;
std::vector<std::wstring> tab_entries = {
L"htop", L"color", L"spinner", L"gauge", L"compiler",
};
Component tab_selection = Toggle(&tab_entries, &tab_index);
Component container =
Container::Tab(&tab_index,
{
std::make_shared<HTopComponent>(),
std::make_shared<ColorComponent>(),
std::make_shared<SpinnerComponent>(),
std::make_shared<GaugeComponent>(),
std::make_shared<CompilerComponent>(),
auto tab_selection = Toggle(&tab_entries, &tab_index);
auto tab_content = Container::Tab(&tab_index, {
htop,
color_tab_renderer,
spinner_tab_renderer,
gauge_component,
compiler_renderer,
});
Component main_container = Container::Vertical({
auto main_container = Container::Vertical({
tab_selection,
container,
tab_content,
});
Tab() { Add(main_container); }
Element Render() override {
auto main_renderer = Renderer(main_container, [&] {
return vbox({
text(L"FTXUI Demo") | bold | hcenter,
tab_selection->Render() | hcenter,
container->Render() | flex,
tab_content->Render() | flex,
});
});
}
};
int main(int argc, const char* argv[]) {
auto screen = ScreenInteractive::Fullscreen();
std::thread update([&screen]() {
std::thread update([&screen, &shift]() {
for (;;) {
using namespace std::chrono_literals;
std::this_thread::sleep_for(0.05s);
@ -393,8 +370,7 @@ int main(int argc, const char* argv[]) {
}
});
Component tab = std::make_shared<Tab>();
screen.Loop(tab);
screen.Loop(main_renderer);
return 0;
}

View File

@ -0,0 +1,83 @@
#include <functional> // for function
#include <memory> // for allocator, __shared_ptr_access
#include <string> // for operator+, to_wstring, char_traits
#include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Slider, Make
#include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/container.hpp" // for Container
#include "ftxui/component/event.hpp" // for Event, Event::Escape, Event::Return
#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
#include "ftxui/dom/elements.hpp" // for separator, operator|, Element, size, text, vbox, xflex, bgcolor, hbox, GREATER_THAN, WIDTH, border, HEIGHT, LESS_THAN
#include "ftxui/screen/color.hpp" // for Color
using namespace ftxui;
Element ColorTile(int red, int green, int blue) {
return text(L"") | size(WIDTH, GREATER_THAN, 14) |
size(HEIGHT, GREATER_THAN, 7) | bgcolor(Color::RGB(red, green, blue));
}
Element ColorString(int red, int green, int blue) {
return text(L"RGB = (" + //
std::to_wstring(red) + L"," + //
std::to_wstring(green) + L"," + //
std::to_wstring(blue) + L")" //
);
}
class MyComponent : public ComponentBase {
private:
int* red_;
int* green_;
int* blue_;
Component slider_red_ = Slider(L"Red :", red_, 0, 255, 1);
Component slider_green_ = Slider(L"Green:", green_, 0, 255, 1);
Component slider_blue_ = Slider(L"Blue :", blue_, 0, 255, 1);
std::function<void(void)> quit_;
public:
MyComponent(int* red, int* green, int* blue, std::function<void(void)> quit)
: red_(red), green_(green), blue_(blue), quit_(quit) {
Add(Container::Vertical({
slider_red_,
slider_green_,
slider_blue_,
}));
}
Element Render() {
return hbox({
ColorTile(*red_, *green_, *blue_),
separator(),
vbox({
slider_red_->Render(),
separator(),
slider_green_->Render(),
separator(),
slider_blue_->Render(),
separator(),
ColorString(*red_, *green_, *blue_),
}) | xflex,
}) |
border | size(WIDTH, LESS_THAN, 80);
}
bool OnEvent(Event event) {
if (event == Event::Return || event == Event::Escape)
quit_();
return ComponentBase::OnEvent(event);
}
};
int main(int argc, const char* argv[]) {
auto screen = ScreenInteractive::TerminalOutput();
int red = 128;
int green = 25;
int blue = 100;
screen.Loop(Make<MyComponent>(&red, &green, &blue, screen.ExitLoopClosure()));
}
// 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.

View File

@ -26,6 +26,8 @@ Component Input(std::wstring* content, const std::wstring* placeholder);
Component Menu(const std::vector<std::wstring>* entries, int* selected_);
Component Radiobox(const std::vector<std::wstring>* entries, int* selected_);
Component Toggle(const std::vector<std::wstring>* entries, int* selected);
Component Renderer(Component child, std::function<Element()>);
Component Renderer(std::function<Element()>);
template <class T> // T = {int, float}
Component Slider(std::wstring label, T* value, T min, T max, T increment);

View File

@ -0,0 +1,44 @@
#include <functional> // for function
#include <memory> // for shared_ptr
#include "ftxui/component/component.hpp" // for Make
#include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/dom/elements.hpp" // for Element
namespace ftxui {
/// @brief A component rendering Element from a function.
/// @ingroup component.
class RendererBase : public ComponentBase {
public:
// Access this interface from a Component
static RendererBase* From(Component component) {
return static_cast<RendererBase*>(component.get());
}
// Constructor.
RendererBase(std::function<Element()> render) : render_(std::move(render)) {}
~RendererBase() override = default;
// Component implementation.
Element Render() override { return render_(); }
protected:
std::function<Element()> render_;
};
Component Renderer(std::function<Element()> render) {
return Make<RendererBase>(std::move(render));
}
Component Renderer(Component child, std::function<Element()> render) {
Component renderer = Renderer(std::move(render));
renderer->Add(std::move(child));
return renderer;
}
} // namespace ftxui
// Copyright 2021 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.