From c9aa1805eb718e607197268c03a8de1a020fece5 Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Thu, 13 May 2021 11:44:47 +0200 Subject: [PATCH] Add the Renderer component. --- CMakeLists.txt | 1 + examples/component/button.cpp | 39 ++- examples/component/checkbox.cpp | 12 +- examples/component/checkbox_in_frame.cpp | 57 ++-- examples/component/gallery.cpp | 162 ++++++------ examples/component/homescreen.cpp | 324 +++++++++++------------ examples/component/slider_rgb.cpp | 83 ++++++ include/ftxui/component/component.hpp | 2 + src/ftxui/component/renderer.cpp | 44 +++ 9 files changed, 400 insertions(+), 324 deletions(-) create mode 100644 examples/component/slider_rgb.cpp create mode 100644 src/ftxui/component/renderer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e9f9bd9..9af4e37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/examples/component/button.cpp b/examples/component/button.cpp index 2716d5c..6382890 100644 --- a/examples/component/button.cpp +++ b/examples/component/button.cpp @@ -1,43 +1,36 @@ #include // 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()); + screen.Loop(component); return 0; } diff --git a/examples/component/checkbox.cpp b/examples/component/checkbox.cpp index 4eb51b1..cd2637e 100644 --- a/examples/component/checkbox.cpp +++ b/examples/component/checkbox.cpp @@ -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()); + screen.Loop(component); return 0; } diff --git a/examples/component/checkbox_in_frame.cpp b/examples/component/checkbox_in_frame.cpp index 1af542b..75b30de 100644 --- a/examples/component/checkbox_in_frame.cpp +++ b/examples/component/checkbox_in_frame.cpp @@ -1,9 +1,7 @@ -#include // for __alloc_traits<>::value_type #include // for unique_ptr, make_unique, __shared_ptr_access #include // for operator+, wstring #include // 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 MakeCheckbox(std::wstring label) { - auto out = std::make_unique(); - 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> checkbox; - Component container = Container::Vertical(); + bool checked; }; int main(int argc, const char* argv[]) { + int size = 30; + std::vector states(size); + auto container = Container::Vertical({}); + for(int i = 0; iAdd(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(); - screen.Loop(my_component); + screen.Loop(component); return 0; } diff --git a/examples/component/gallery.cpp b/examples/component/gallery.cpp index 329a7ec..1d3564e 100644 --- a/examples/component/gallery.cpp +++ b/examples/component/gallery.cpp @@ -12,111 +12,117 @@ using namespace ftxui; -class MyComponent : public ComponentBase { - const std::vector 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 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 toggle_entries_ = { + // -- Toggle------------------------------------------------------------------ + int toggle_selected = 0; + std::vector 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 radiobox_entries_ = { + // -- Radiobox --------------------------------------------------------------- + int radiobox_selected = 0; + std::vector 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 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 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, + toggle->Render(), + separator(), + checkboxes->Render(), + separator(), + radiobox->Render(), + separator(), + input->Render(), + separator(), + sliders->Render(), + separator(), + button->Render(), }) | - xflex; - } + xflex | size(WIDTH, GREATER_THAN, 40) | border; + }); - Element Render(std::wstring name, Component& component) { - return Render(name, component->Render()); - } - - Element Render() override { - return // - vbox({ - Render(L"menu", menu_), - separator(), - Render(L"toggle", toggle_), - separator(), - Render(L"checkbox", checkbox_container_), - separator(), - Render(L"radiobox", radiobox_), - separator(), - Render(L"input", input_) | size(WIDTH, LESS_THAN, 50), - separator(), - Render(L"slider", slider_container_), - separator(), - Render(L"button", button_), - }) | - xflex | size(WIDTH, GREATER_THAN, 40) | border; - } - - std::function on_quit_; -}; - -int main(int argc, const char* argv[]) { - auto screen = ScreenInteractive::FitComponent(); - auto component = Make(screen.ExitLoopClosure()); screen.Loop(component); return 0; diff --git a/examples/component/homescreen.cpp b/examples/component/homescreen.cpp index 407e11b..876c3c2 100644 --- a/examples/component/homescreen.cpp +++ b/examples/component/homescreen.cpp @@ -20,32 +20,32 @@ using namespace ftxui; -int shift = 0; -class Graph { - public: - std::vector operator()(int width, int height) { - std::vector 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 *= height; - v += 0.5f * height; - output[i] = (int)v; +int main(int argc, const char* argv[]) { + auto screen = ScreenInteractive::Fullscreen(); + + int shift = 0; + + class Graph { + public: + Graph(int* shift) : shift_(shift) {} + std::vector operator()(int width, int height) { + std::vector 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 *= height; + v += 0.5f * height; + output[i] = (int)v; + } + return output; } - 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,52 +98,50 @@ class HTopComponent : public ComponentBase { ram | flex, }) | flex | border; - } -}; + }); -const std::vector compiler_entries = { - L"gcc", - L"clang", - L"emcc", - L"game_maker", - L"Ada compilers", - L"ALGOL 60 compilers", - L"ALGOL 68 compilers", - L"Assemblers (Intel *86)", - L"Assemblers (Motorola 68*)", - L"Assemblers (Zilog Z80)", - L"Assemblers (other)", - L"BASIC Compilers", - L"BASIC interpreters", - L"Batch compilers", - L"C compilers", - L"Source-to-source compilers", - L"C++ compilers", - L"C# compilers", - L"COBOL compilers", - L"Common Lisp compilers", - L"D compilers", - L"DIBOL/DBL compilers", - L"ECMAScript interpreters", - L"Eiffel compilers", - L"Fortran compilers", - L"Go compilers", - L"Haskell compilers", - L"Java compilers", - L"Pascal compilers", - L"Perl Interpreters", - L"PHP compilers", - L"PL/I compilers", - L"Python compilers", - L"Scheme compilers and interpreters", - L"Smalltalk compilers", - L"Tcl Interpreters", - L"VMS Interpreters", - L"Rexx Interpreters", - L"CLI compilers", -}; + const std::vector compiler_entries = { + L"gcc", + L"clang", + L"emcc", + L"game_maker", + L"Ada compilers", + L"ALGOL 60 compilers", + L"ALGOL 68 compilers", + L"Assemblers (Intel *86)", + L"Assemblers (Motorola 68*)", + L"Assemblers (Zilog Z80)", + L"Assemblers (other)", + L"BASIC Compilers", + L"BASIC interpreters", + L"Batch compilers", + L"C compilers", + L"Source-to-source compilers", + L"C++ compilers", + L"C# compilers", + L"COBOL compilers", + L"Common Lisp compilers", + L"D compilers", + L"DIBOL/DBL compilers", + L"ECMAScript interpreters", + L"Eiffel compilers", + L"Fortran compilers", + L"Go compilers", + L"Haskell compilers", + L"Java compilers", + L"Pascal compilers", + L"Perl Interpreters", + L"PHP compilers", + L"PL/I compilers", + L"Python compilers", + L"Scheme compilers and interpreters", + L"Smalltalk compilers", + L"Tcl Interpreters", + 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,28 +176,48 @@ class CompilerComponent : public ComponentBase { Checkbox(&options_label[3], &options_state[3]), }); - public: - ~CompilerComponent() override {} - CompilerComponent() { - Add(Container::Horizontal({ - compiler, - flags, - Container::Vertical({ - executable_, - Container::Horizontal({ - input_add, - input, - }), - }), - })); + auto compiler_component = Container::Horizontal({ + compiler, + flags, + Container::Vertical({ + executable_, + Container::Horizontal({ + input_add, + input, + }), + }), + }); - InputBase::From(input_add)->on_enter = [this] { - input_entries.push_back(input_add_content); - input_add_content = L""; - }; - } + 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); + 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 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(), - std::make_shared(), - std::make_shared(), - std::make_shared(), - std::make_shared(), - }); + 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(); - screen.Loop(tab); + screen.Loop(main_renderer); return 0; } diff --git a/examples/component/slider_rgb.cpp b/examples/component/slider_rgb.cpp new file mode 100644 index 0000000..1d04601 --- /dev/null +++ b/examples/component/slider_rgb.cpp @@ -0,0 +1,83 @@ +#include // for function +#include // for allocator, __shared_ptr_access +#include // 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 quit_; + + public: + MyComponent(int* red, int* green, int* blue, std::function 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(&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. diff --git a/include/ftxui/component/component.hpp b/include/ftxui/component/component.hpp index 882e10b..b32459d 100644 --- a/include/ftxui/component/component.hpp +++ b/include/ftxui/component/component.hpp @@ -26,6 +26,8 @@ Component Input(std::wstring* content, const std::wstring* placeholder); Component Menu(const std::vector* entries, int* selected_); Component Radiobox(const std::vector* entries, int* selected_); Component Toggle(const std::vector* entries, int* selected); +Component Renderer(Component child, std::function); +Component Renderer(std::function); template // T = {int, float} Component Slider(std::wstring label, T* value, T min, T max, T increment); diff --git a/src/ftxui/component/renderer.cpp b/src/ftxui/component/renderer.cpp new file mode 100644 index 0000000..27a0c9e --- /dev/null +++ b/src/ftxui/component/renderer.cpp @@ -0,0 +1,44 @@ +#include // for function +#include // 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(component.get()); + } + + // Constructor. + RendererBase(std::function render) : render_(std::move(render)) {} + ~RendererBase() override = default; + + // Component implementation. + Element Render() override { return render_(); } + + protected: + std::function render_; +}; + +Component Renderer(std::function render) { + return Make(std::move(render)); +} + +Component Renderer(Component child, std::function 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.