mirror of
				https://github.com/ArthurSonzogni/FTXUI.git
				synced 2025-10-31 18:48:11 +08:00 
			
		
		
		
	Make component more functionnal
This commit is contained in:
		| @@ -80,6 +80,7 @@ add_library(component | ||||
|   include/ftxui/component/captured_mouse.hpp | ||||
|   include/ftxui/component/checkbox.hpp | ||||
|   include/ftxui/component/component.hpp | ||||
|   include/ftxui/component/component_base.hpp | ||||
|   include/ftxui/component/container.hpp | ||||
|   include/ftxui/component/event.hpp | ||||
|   include/ftxui/component/input.hpp | ||||
| @@ -88,7 +89,6 @@ add_library(component | ||||
|   include/ftxui/component/radiobox.hpp | ||||
|   include/ftxui/component/receiver.hpp | ||||
|   include/ftxui/component/screen_interactive.hpp | ||||
|   include/ftxui/component/slider.hpp | ||||
|   include/ftxui/component/toggle.hpp | ||||
|   src/ftxui/component/button.cpp | ||||
|   src/ftxui/component/checkbox.cpp | ||||
|   | ||||
| @@ -34,6 +34,7 @@ | ||||
| @example ./examples/component/input.cpp | ||||
| @example ./examples/component/homescreen.cpp | ||||
| @example ./examples/component/radiobox.cpp | ||||
| @example ./examples/component/slider_rgb.cpp | ||||
| @example ./examples/component/menu.cpp | ||||
| @example ./examples/component/menu_style.cpp | ||||
| @example ./examples/component/radiobox_in_frame.cpp | ||||
|   | ||||
| @@ -31,7 +31,7 @@ int main(void) { | ||||
|     Dimension::Fit(document) // Height | ||||
|   ); | ||||
|   Render(screen, document); | ||||
|   std::cout << screen.ToString() << std::endl; | ||||
|   screen.Print(); | ||||
|  | ||||
|   return EXIT_SUCCESS; | ||||
| } | ||||
| @@ -142,6 +142,13 @@ This provides: | ||||
| 3. A predefined implementation of "keyboard navigation". | ||||
| 4. A set of predefined widget: CheckBox, RadioBox, Input, Menu, Toggle. | ||||
|  | ||||
|  | ||||
| **List of Component** | ||||
|  | ||||
| You only need one header: ftxui/dom/component.hpp | ||||
|  | ||||
| \include ftxui/component/component.hpp | ||||
|  | ||||
| # ftxui/dom | ||||
|  | ||||
| Every elements of the dom are declared from: | ||||
|   | ||||
| @@ -17,6 +17,7 @@ example(modal_dialog) | ||||
| example(radiobox) | ||||
| example(radiobox_in_frame) | ||||
| example(slider) | ||||
| example(slider_rgb) | ||||
| example(tab_horizontal) | ||||
| example(tab_vertical) | ||||
| example(toggle) | ||||
|   | ||||
| @@ -1,51 +1,43 @@ | ||||
| #include <functional>  // for function | ||||
| #include <memory>      // for unique_ptr, make_u... | ||||
| #include <string>      // for wstring | ||||
| #include <utility>     // for move | ||||
| #include <vector>      // for vector | ||||
| #include <string>  // for operator+, to_wstring, allocator, wstring | ||||
|  | ||||
| #include "ftxui/component/button.hpp"              // for Button | ||||
| #include "ftxui/component/component.hpp"           // for Component | ||||
| #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/screen/box.hpp"                    // for ftxui | ||||
| #include "ftxui/dom/elements.hpp"  // for separator, Element, gauge, text, operator|, vbox, border | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| class MyComponent : public Component { | ||||
| class MyComponent : public ComponentBase { | ||||
|  private: | ||||
|   std::vector<std::unique_ptr<Button>> buttons_; | ||||
|   Container container_ = Container::Horizontal(); | ||||
|   std::wstring label_add = L"Increase"; | ||||
|   std::wstring label_rm = L"Decrease"; | ||||
|   int value_ = 50; | ||||
|  | ||||
|  public: | ||||
|   MyComponent() { | ||||
|     Add(&container_); | ||||
|     Add(Container::Horizontal({ | ||||
|         Button(&label_rm, [&] { value_--; }), | ||||
|         Button(&label_add, [&] { value_++; }), | ||||
|     })); | ||||
|   } | ||||
|  | ||||
|     auto button_add = std::make_unique<Button>(); | ||||
|     auto button_remove = std::make_unique<Button>(); | ||||
|     container_.Add(button_add.get()); | ||||
|     container_.Add(button_remove.get()); | ||||
|     button_add->label = L"Add one button"; | ||||
|     button_remove->label = L"Remove last button"; | ||||
|  | ||||
|     button_add->on_click = [&] { | ||||
|       auto extra_button = std::make_unique<Button>(); | ||||
|       extra_button->label = L"extra button"; | ||||
|       container_.Add(extra_button.get()); | ||||
|       buttons_.push_back(std::move(extra_button)); | ||||
|     }; | ||||
|  | ||||
|     button_remove->on_click = [&] { buttons_.resize(buttons_.size() - 1); }; | ||||
|  | ||||
|     buttons_.push_back(std::move(button_add)); | ||||
|     buttons_.push_back(std::move(button_remove)); | ||||
|   Element Render() override { | ||||
|     return vbox({ | ||||
|                text(L"Value = " + std::to_wstring(value_)), | ||||
|                separator(), | ||||
|                gauge(value_ * 0.01f), | ||||
|                separator(), | ||||
|                ComponentBase::Render(), | ||||
|            }) | | ||||
|            border; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   auto screen = ScreenInteractive::TerminalOutput(); | ||||
|   MyComponent component; | ||||
|   screen.Loop(&component); | ||||
|   auto screen = ScreenInteractive::FitComponent(); | ||||
|   screen.Loop(Make<MyComponent>()); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,34 +1,34 @@ | ||||
| #include "ftxui/component/checkbox.hpp" | ||||
| #include "ftxui/component/component.hpp"           // for Component | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for ftxui | ||||
| #include "ftxui/component/component.hpp"       // for Checkbox, Make | ||||
| #include "ftxui/component/container.hpp"       // for Container | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for ScreenInteractive | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for ScreenInteractive, Component | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| class MyComponent : public Component { | ||||
| class MyComponent : public ComponentBase { | ||||
|  private: | ||||
|   CheckBox box_1_; | ||||
|   CheckBox box_2_; | ||||
|   CheckBox box_3_; | ||||
|   Container container_ = Container::Vertical(); | ||||
|   std::wstring build_examples_label = L"Build examples"; | ||||
|   std::wstring build_tests_label = L"Build tests"; | ||||
|   std::wstring use_webassembly_label = L"Use WebAssembly"; | ||||
|  | ||||
|   bool build_examples_state = false; | ||||
|   bool build_tests_state = false; | ||||
|   bool use_webassembly_state = true; | ||||
|  | ||||
|   Component container = 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_); | ||||
|     container_.Add(&box_1_); | ||||
|     container_.Add(&box_2_); | ||||
|     container_.Add(&box_3_); | ||||
|     box_1_.label = L"Build examples"; | ||||
|     box_2_.label = L"Build tests"; | ||||
|     box_3_.label = L"Use WebAssembly"; | ||||
|     box_3_.state = true; | ||||
|   } | ||||
|   MyComponent() { Add(container); } | ||||
| }; | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   auto screen = ScreenInteractive::TerminalOutput(); | ||||
|   MyComponent component; | ||||
|   screen.Loop(&component); | ||||
|   screen.Loop(Make<MyComponent>()); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,50 +1,61 @@ | ||||
| #include <memory>   // for allocator_traits<>... | ||||
| #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 <utility>  // for move | ||||
| #include <vector>  // for vector | ||||
|  | ||||
| #include "ftxui/component/checkbox.hpp"            // for CheckBox | ||||
| #include "ftxui/component/component.hpp"           // for Component | ||||
| #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 | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for ScreenInteractive | ||||
| #include "ftxui/dom/elements.hpp"                  // for Element, operator| | ||||
| #include "ftxui/screen/box.hpp"                    // for ftxui | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for Component, ScreenInteractive | ||||
| #include "ftxui/dom/elements.hpp"  // for Element, operator|, size, vbox, border, frame, Elements, HEIGHT, LESS_THAN | ||||
| #include "ftxui/screen/string.hpp"  // for to_wstring | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| class MyComponent : public Component { | ||||
| struct CheckboxAndState { | ||||
|   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); | ||||
|     Add(container); | ||||
|     checkbox.resize(30); | ||||
|     for (int i = 0; i < checkbox.size(); ++i) { | ||||
|       checkbox[i].label = (L"CheckBox " + to_wstring(i)); | ||||
|       container.Add(&checkbox[i]); | ||||
|       checkbox[i] = MakeCheckbox(L"CheckBox " + to_wstring(i)); | ||||
|       container->Add(checkbox[i]->component); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // clang-format off | ||||
|   Element Render() override { | ||||
|     Elements content; | ||||
|     for (auto& it : checkbox) { | ||||
|       content.push_back(it.Render()); | ||||
|     } | ||||
|     return vbox(std::move(content)) | ||||
|     return vbox(container->Render()) | ||||
|       | frame | ||||
|       | size(HEIGHT, LESS_THAN, 10) | ||||
|       | border; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   std::vector<CheckBox> checkbox; | ||||
|   Container container = Container::Vertical(); | ||||
|   std::vector<std::unique_ptr<CheckboxAndState>> checkbox; | ||||
|   Component container = Container::Vertical(); | ||||
| }; | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   auto screen = ScreenInteractive::FitComponent(); | ||||
|   MyComponent component; | ||||
|   screen.Loop(&component); | ||||
|   auto my_component = Make<MyComponent>(); | ||||
|   screen.Loop(my_component); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|   | ||||
| @@ -1,82 +1,81 @@ | ||||
| #include <functional>  // for function | ||||
| #include <memory>      // for allocator, unique_ptr | ||||
| #include <string>      // for wstring | ||||
| #include <memory>      // for allocator, __shared_ptr_access | ||||
| #include <string>      // for wstring, basic_string | ||||
| #include <vector>      // for vector | ||||
|  | ||||
| #include "ftxui/component/button.hpp"              // for Button | ||||
| #include "ftxui/component/checkbox.hpp"            // for CheckBox | ||||
| #include "ftxui/component/component.hpp"           // for Component, Compone... | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for ftxui | ||||
| #include "ftxui/component/component.hpp"  // for Slider, Checkbox, Button, Input, Make, Menu, Radiobox, Toggle | ||||
| #include "ftxui/component/component_base.hpp"  // for ComponentBase | ||||
| #include "ftxui/component/container.hpp"       // for Container | ||||
| #include "ftxui/component/input.hpp"               // for Input | ||||
| #include "ftxui/component/menu.hpp"                // for Menu | ||||
| #include "ftxui/component/radiobox.hpp"            // for RadioBox | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for ScreenInteractive | ||||
| #include "ftxui/component/slider.hpp"              // for Slider | ||||
| #include "ftxui/component/toggle.hpp"              // for Toggle | ||||
| #include "ftxui/dom/elements.hpp"                  // for separator, operator| | ||||
| #include "ftxui/screen/box.hpp"                    // for ftxui | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for Component, ScreenInteractive | ||||
| #include "ftxui/dom/elements.hpp"  // for separator, operator|, Element, size, xflex, text, WIDTH, hbox, vbox, EQUAL, LESS_THAN, border, GREATER_THAN | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| class MyComponent : public Component { | ||||
|   Container container = Container::Vertical(); | ||||
|   Menu menu; | ||||
|   Toggle toggle; | ||||
|   Container checkbox_container = Container::Vertical(); | ||||
|   CheckBox checkbox1; | ||||
|   CheckBox checkbox2; | ||||
|   RadioBox radiobox; | ||||
|   Input input; | ||||
|   Button button; | ||||
|  | ||||
|   int slider_value_1_ = 12; | ||||
|   int slider_value_2_ = 56; | ||||
|   int slider_value_3_ = 128; | ||||
|   ComponentPtr slider_1_ = Slider(L"R:", &slider_value_1_, 0, 256, 1); | ||||
|   ComponentPtr slider_2_ = Slider(L"G:", &slider_value_2_, 0, 256, 1); | ||||
|   ComponentPtr slider_3_ = Slider(L"B:", &slider_value_3_, 0, 256, 1); | ||||
|  | ||||
|  public: | ||||
|   MyComponent() { | ||||
|     Add(&container); | ||||
|     menu.entries = { | ||||
| class MyComponent : public ComponentBase { | ||||
|   const std::vector<std::wstring> menu_entries_ = { | ||||
|       L"Menu 1", | ||||
|       L"Menu 2", | ||||
|       L"Menu 3", | ||||
|       L"Menu 4", | ||||
|   }; | ||||
|     container.Add(&menu); | ||||
|   int menu_selected_ = 0; | ||||
|   Component menu_ = Menu(&menu_entries_, &menu_selected_); | ||||
|  | ||||
|     toggle.entries = { | ||||
|   int toggle_selected_ = 0; | ||||
|   std::vector<std::wstring> toggle_entries_ = { | ||||
|       L"Toggle_1", | ||||
|       L"Toggle_2", | ||||
|   }; | ||||
|     container.Add(&toggle); | ||||
|   Component toggle_ = Toggle(&toggle_entries_, &toggle_selected_); | ||||
|  | ||||
|     container.Add(&checkbox_container); | ||||
|     checkbox1.label = L"checkbox1"; | ||||
|     checkbox_container.Add(&checkbox1); | ||||
|     checkbox2.label = L"checkbox2"; | ||||
|     checkbox_container.Add(&checkbox2); | ||||
|   std::wstring checkbox_1_label_ = L"checkbox1"; | ||||
|   std::wstring checkbox_2_label_ = L"checkbox2"; | ||||
|   bool checkbox_1_selected_ = false; | ||||
|   bool checkbox_2_selected_ = false; | ||||
|  | ||||
|     radiobox.entries = { | ||||
|   Component checkbox_container_ = Container::Vertical({ | ||||
|       Checkbox(&checkbox_1_label_, &checkbox_1_selected_), | ||||
|       Checkbox(&checkbox_2_label_, &checkbox_2_selected_), | ||||
|   }); | ||||
|  | ||||
|   int radiobox_selected_ = 0; | ||||
|   std::vector<std::wstring> radiobox_entries_ = { | ||||
|       L"Radiobox 1", | ||||
|       L"Radiobox 2", | ||||
|       L"Radiobox 3", | ||||
|       L"Radiobox 4", | ||||
|   }; | ||||
|     container.Add(&radiobox); | ||||
|   Component radiobox_ = Radiobox(&radiobox_entries_, &radiobox_selected_); | ||||
|  | ||||
|     input.placeholder = L"Input placeholder"; | ||||
|     container.Add(&input); | ||||
|   std::wstring input_label_; | ||||
|   std::wstring input_placeholder_ = L"input"; | ||||
|   Component input_ = Input(&input_label_, &input_placeholder_); | ||||
|  | ||||
|     container.Add(slider_1_.get()); | ||||
|     container.Add(slider_2_.get()); | ||||
|     container.Add(slider_3_.get()); | ||||
|   std::wstring button_label_ = L"Quit"; | ||||
|   std::function<void()> on_button_clicked_; | ||||
|   Component button_ = Button(&button_label_, [this] { on_button_clicked_(); }); | ||||
|  | ||||
|     button.label = L"Quit"; | ||||
|     button.on_click = [&] { on_quit(); }; | ||||
|     container.Add(&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), | ||||
|   }); | ||||
|  | ||||
|  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) { | ||||
| @@ -89,42 +88,36 @@ class MyComponent : public Component { | ||||
|   } | ||||
|  | ||||
|   Element Render(std::wstring name, Component& component) { | ||||
|     return Render(name, component.Render()); | ||||
|     return Render(name, component->Render()); | ||||
|   } | ||||
|  | ||||
|   Element Render() override { | ||||
|     return  // | ||||
|         vbox({ | ||||
|             Render(L"menu", menu), | ||||
|             Render(L"menu", menu_), | ||||
|             separator(), | ||||
|             Render(L"toggle", toggle), | ||||
|             Render(L"toggle", toggle_), | ||||
|             separator(), | ||||
|             Render(L"checkbox", checkbox_container), | ||||
|             Render(L"checkbox", checkbox_container_), | ||||
|             separator(), | ||||
|             Render(L"radiobox", radiobox), | ||||
|             Render(L"radiobox", radiobox_), | ||||
|             separator(), | ||||
|             Render(L"input", input) | size(WIDTH, LESS_THAN, 50), | ||||
|             Render(L"input", input_) | size(WIDTH, LESS_THAN, 50), | ||||
|             separator(), | ||||
|             Render(L"slider",  // | ||||
|                    vbox({ | ||||
|                        slider_1_->Render(), | ||||
|                        slider_2_->Render(), | ||||
|                        slider_3_->Render(), | ||||
|                    })), | ||||
|             Render(L"slider", slider_container_), | ||||
|             separator(), | ||||
|             Render(L"button", button), | ||||
|             Render(L"button", button_), | ||||
|         }) | | ||||
|         xflex | size(WIDTH, GREATER_THAN, 40) | border; | ||||
|   } | ||||
|  | ||||
|   std::function<void()> on_quit = [] {}; | ||||
|   std::function<void()> on_quit_; | ||||
| }; | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   auto screen = ScreenInteractive::FitComponent(); | ||||
|   MyComponent component; | ||||
|   component.on_quit = screen.ExitLoopClosure(); | ||||
|   screen.Loop(&component); | ||||
|   auto component = Make<MyComponent>(screen.ExitLoopClosure()); | ||||
|   screen.Loop(component); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|   | ||||
| @@ -1,23 +1,22 @@ | ||||
| #include <chrono>      // for operator""s, chron... | ||||
| #include <array>       // for array | ||||
| #include <chrono>      // for operator""s, chrono_literals | ||||
| #include <cmath>       // for sin | ||||
| #include <functional>  // for ref, reference_wra... | ||||
| #include <string>      // for allocator, wstring | ||||
| #include <functional>  // for ref, reference_wrapper, function | ||||
| #include <memory>      // for make_shared, __shared_ptr_access | ||||
| #include <string>  // for allocator, wstring, basic_string, operator+, to_wstring | ||||
| #include <thread>   // for sleep_for, thread | ||||
| #include <utility>  // for move | ||||
| #include <vector>   // for vector | ||||
|  | ||||
| #include "ftxui/component/checkbox.hpp"            // for CheckBox | ||||
| #include "ftxui/component/component.hpp"           // for Component | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for ftxui | ||||
| #include "ftxui/component/component.hpp"  // for Checkbox, Input, Menu, Radiobox, Toggle | ||||
| #include "ftxui/component/component_base.hpp"  // for ComponentBase | ||||
| #include "ftxui/component/container.hpp"       // for Container | ||||
| #include "ftxui/component/event.hpp"           // for Event, Event::Custom | ||||
| #include "ftxui/component/input.hpp"               // for Input | ||||
| #include "ftxui/component/menu.hpp"                // for Menu | ||||
| #include "ftxui/component/radiobox.hpp"            // for RadioBox | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for ScreenInteractive | ||||
| #include "ftxui/component/toggle.hpp"              // for Toggle | ||||
| #include "ftxui/dom/elements.hpp"                  // for text, operator| | ||||
| #include "ftxui/screen/box.hpp"                    // for ftxui | ||||
| #include "ftxui/screen/color.hpp"                  // for Color, Color::Blue... | ||||
| #include "ftxui/component/input.hpp"           // for InputBase | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for Component, ScreenInteractive | ||||
| #include "ftxui/dom/elements.hpp"  // for text, operator|, color, bgcolor, Element, filler, size, vbox, flex, hbox, graph, separator, EQUAL, WIDTH, hcenter, bold, border, window, Elements, HEIGHT, hflow, flex_grow, frame, gauge, LESS_THAN, spinner, dim, GREATER_THAN | ||||
| #include "ftxui/screen/color.hpp"  // for Color, Color::BlueLight, Color::RedLight, Color::Black, Color::Blue, Color::Cyan, Color::CyanLight, Color::GrayDark, Color::GrayLight, Color::Green, Color::GreenLight, Color::Magenta, Color::MagentaLight, Color::Red, Color::White, Color::Yellow, Color::YellowLight, Color::Default | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| @@ -39,7 +38,7 @@ class Graph { | ||||
|   } | ||||
| }; | ||||
|  | ||||
| class HTopComponent : public Component { | ||||
| class HTopComponent : public ComponentBase { | ||||
|   Graph my_graph; | ||||
|  | ||||
|  public: | ||||
| @@ -102,24 +101,7 @@ class HTopComponent : public Component { | ||||
|   } | ||||
| }; | ||||
|  | ||||
| class CompilerComponent : public Component { | ||||
|   Container container = Container::Horizontal(); | ||||
|   RadioBox compiler; | ||||
|   Container flag = Container::Vertical(); | ||||
|   CheckBox flag_checkbox[4]; | ||||
|   Container subcontainer = Container::Vertical(); | ||||
|   Container input_container = Container::Horizontal(); | ||||
|   Input input_add; | ||||
|   Menu input; | ||||
|   Input executable; | ||||
|  | ||||
|  public: | ||||
|   ~CompilerComponent() override {} | ||||
|   CompilerComponent() { | ||||
|     Add(&container); | ||||
|  | ||||
|     // Compiler ---------------------------------------------------------------- | ||||
|     compiler.entries = { | ||||
| const std::vector<std::wstring> compiler_entries = { | ||||
|     L"gcc", | ||||
|     L"clang", | ||||
|     L"emcc", | ||||
| @@ -159,53 +141,81 @@ class CompilerComponent : public Component { | ||||
|     L"VMS Interpreters", | ||||
|     L"Rexx Interpreters", | ||||
|     L"CLI compilers", | ||||
| }; | ||||
|  | ||||
| class CompilerComponent : public ComponentBase { | ||||
|   int compiler_selected = 0; | ||||
|   Component compiler = Radiobox(&compiler_entries, &compiler_selected); | ||||
|  | ||||
|   std::array<std::wstring, 4> options_label = { | ||||
|       L"-Wall", | ||||
|       L"-Werror", | ||||
|       L"-lpthread", | ||||
|       L"-O3", | ||||
|   }; | ||||
|     container.Add(&compiler); | ||||
|  | ||||
|     // Flags    ---------------------------------------------------------------- | ||||
|     container.Add(&flag); | ||||
|     flag_checkbox[0].label = L"-Wall"; | ||||
|     flag_checkbox[1].label = L"-Werror"; | ||||
|     flag_checkbox[2].label = L"-lpthread"; | ||||
|     flag_checkbox[3].label = L"-O3"; | ||||
|     for (auto& c : flag_checkbox) | ||||
|       flag.Add(&c); | ||||
|  | ||||
|     container.Add(&subcontainer); | ||||
|     // Executable | ||||
|     // ---------------------------------------------------------------- | ||||
|     executable.placeholder = L"executable"; | ||||
|     subcontainer.Add(&executable); | ||||
|  | ||||
|     // Input    ---------------------------------------------------------------- | ||||
|     subcontainer.Add(&input_container); | ||||
|  | ||||
|     input_add.placeholder = L"input files"; | ||||
|     input_add.on_enter = [this] { | ||||
|       input.entries.push_back(input_add.content); | ||||
|       input_add.content = L""; | ||||
|   std::array<bool, 4> options_state = { | ||||
|       false, | ||||
|       false, | ||||
|       false, | ||||
|       false, | ||||
|   }; | ||||
|   std::wstring input_add_content = L""; | ||||
|   std::wstring input_add_placeholder = L"input_files"; | ||||
|   Component input_add = Input(&input_add_content, &input_add_placeholder); | ||||
|  | ||||
|   std::vector<std::wstring> input_entries; | ||||
|   int input_selected = 0; | ||||
|   Component input = Menu(&input_entries, &input_selected); | ||||
|  | ||||
|   std::wstring executable_content_ = L""; | ||||
|   std::wstring executable_placeholder_ = L"executable"; | ||||
|   Component executable_ = Input(&executable_content_, &executable_placeholder_); | ||||
|  | ||||
|   Component flags = Container::Vertical({ | ||||
|       Checkbox(&options_label[0], &options_state[0]), | ||||
|       Checkbox(&options_label[1], &options_state[1]), | ||||
|       Checkbox(&options_label[2], &options_state[2]), | ||||
|       Checkbox(&options_label[3], &options_state[3]), | ||||
|   }); | ||||
|  | ||||
|  public: | ||||
|   ~CompilerComponent() override {} | ||||
|   CompilerComponent() { | ||||
|     Add(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""; | ||||
|     }; | ||||
|     input_container.Add(&input_add); | ||||
|     input_container.Add(&input); | ||||
|   } | ||||
|  | ||||
|   Element Render() override { | ||||
|     auto compiler_win = window(text(L"Compiler"), compiler.Render() | frame); | ||||
|     auto flags_win = window(text(L"Flags"), flag.Render()); | ||||
|     auto executable_win = window(text(L"Executable:"), executable.Render()); | ||||
|     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()); | ||||
|     auto input_win = | ||||
|         window(text(L"Input"), | ||||
|                hbox({ | ||||
|                    vbox({ | ||||
|                        hbox({ | ||||
|                            text(L"Add: "), | ||||
|                            input_add.Render(), | ||||
|                            input_add->Render(), | ||||
|                        }) | size(WIDTH, EQUAL, 20) | | ||||
|                            size(HEIGHT, EQUAL, 1), | ||||
|                        filler(), | ||||
|                    }), | ||||
|                    separator(), | ||||
|                    input.Render() | frame | size(HEIGHT, EQUAL, 3) | flex, | ||||
|                    input->Render() | frame | size(HEIGHT, EQUAL, 3) | flex, | ||||
|                })); | ||||
|     return vbox({ | ||||
|                hbox({ | ||||
| @@ -225,28 +235,29 @@ class CompilerComponent : public Component { | ||||
|   Elements RenderCommandLine() { | ||||
|     Elements line; | ||||
|     // Compiler | ||||
|     line.push_back(text(compiler.entries[compiler.selected]) | bold); | ||||
|     line.push_back(text(compiler_entries[compiler_selected]) | bold); | ||||
|     // flags | ||||
|     for (auto& it : flag_checkbox) { | ||||
|       if (it.state) { | ||||
|     for (int i = 0; i < 4; ++i) { | ||||
|       if (options_state[i]) { | ||||
|         line.push_back(text(L" ")); | ||||
|         line.push_back(text(it.label) | dim); | ||||
|         line.push_back(text(options_label[i]) | dim); | ||||
|       } | ||||
|     } | ||||
|     // Executable | ||||
|     if (!executable.content.empty()) { | ||||
|     if (!executable_content_.empty()) { | ||||
|       line.push_back(text(L" -O ") | bold); | ||||
|       line.push_back(text(executable.content) | color(Color::BlueLight) | bold); | ||||
|       line.push_back(text(executable_content_) | color(Color::BlueLight) | | ||||
|                      bold); | ||||
|     } | ||||
|     // Input | ||||
|     for (auto& it : input.entries) { | ||||
|     for (auto& it : input_entries) { | ||||
|       line.push_back(text(L" " + it) | color(Color::RedLight)); | ||||
|     } | ||||
|     return line; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| class SpinnerComponent : public Component { | ||||
| class SpinnerComponent : public ComponentBase { | ||||
|   Element Render() override { | ||||
|     Elements entries; | ||||
|     for (int i = 0; i < 22; ++i) { | ||||
| @@ -258,7 +269,7 @@ class SpinnerComponent : public Component { | ||||
|   } | ||||
| }; | ||||
|  | ||||
| class ColorComponent : public Component { | ||||
| class ColorComponent : public ComponentBase { | ||||
|   Element Render() override { | ||||
|     return hbox({ | ||||
|                vbox({ | ||||
| @@ -304,7 +315,7 @@ class ColorComponent : public Component { | ||||
|   } | ||||
| }; | ||||
|  | ||||
| class GaugeComponent : public Component { | ||||
| class GaugeComponent : public ComponentBase { | ||||
|   Element RenderGauge(int delta) { | ||||
|     float progress = (shift + delta) % 1000 / 1000.f; | ||||
|     return hbox({ | ||||
| @@ -337,38 +348,35 @@ class GaugeComponent : public Component { | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| class Tab : public Component { | ||||
| class Tab : public ComponentBase { | ||||
|  public: | ||||
|   Container main_container = Container::Vertical(); | ||||
|  | ||||
|   Toggle tab_selection; | ||||
|   Container container = Container::Tab(&tab_selection.selected); | ||||
|  | ||||
|   HTopComponent htop_component; | ||||
|   ColorComponent color_component; | ||||
|   SpinnerComponent spinner_component; | ||||
|   GaugeComponent gauge_component; | ||||
|   CompilerComponent compiler_component; | ||||
|  | ||||
|   Tab() { | ||||
|     Add(&main_container); | ||||
|     main_container.Add(&tab_selection); | ||||
|     tab_selection.entries = { | ||||
|   int tab_index = 0; | ||||
|   std::vector<std::wstring> tab_entries = { | ||||
|       L"htop", L"color", L"spinner", L"gauge", L"compiler", | ||||
|   }; | ||||
|     main_container.Add(&container); | ||||
|     container.Add(&htop_component); | ||||
|     container.Add(&color_component); | ||||
|     container.Add(&spinner_component); | ||||
|     container.Add(&gauge_component); | ||||
|     container.Add(&compiler_component); | ||||
|   } | ||||
|   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>(), | ||||
|                      }); | ||||
|  | ||||
|   Component main_container = Container::Vertical({ | ||||
|       tab_selection, | ||||
|       container, | ||||
|   }); | ||||
|  | ||||
|   Tab() { Add(main_container); } | ||||
|  | ||||
|   Element Render() override { | ||||
|     return vbox({ | ||||
|         text(L"FTXUI Demo") | bold | hcenter, | ||||
|         tab_selection.Render() | hcenter, | ||||
|         container.Render() | flex, | ||||
|         tab_selection->Render() | hcenter, | ||||
|         container->Render() | flex, | ||||
|     }); | ||||
|   } | ||||
| }; | ||||
| @@ -385,8 +393,8 @@ int main(int argc, const char* argv[]) { | ||||
|     } | ||||
|   }); | ||||
|  | ||||
|   Tab tab; | ||||
|   screen.Loop(&tab); | ||||
|   Component tab = std::make_shared<Tab>(); | ||||
|   screen.Loop(tab); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|   | ||||
| @@ -1,44 +1,45 @@ | ||||
| #include "ftxui/component/input.hpp" | ||||
| #include <memory>  // for allocator, __shared_ptr_access | ||||
| #include <string>  // for operator+, wstring, char_traits | ||||
|  | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for ftxui | ||||
| #include "ftxui/component/component.hpp"       // for Input, 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/component/screen_interactive.hpp"  // for Component, ScreenInteractive | ||||
| #include "ftxui/dom/elements.hpp"  // for text, hbox, separator, border, vbox, Element | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| class MyComponent : public Component { | ||||
|  public: | ||||
|   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"; | ||||
|   } | ||||
|  | ||||
|   std::function<void()> on_enter = []() {}; | ||||
|  | ||||
| class MyComponent : public ComponentBase { | ||||
|  private: | ||||
|   Container container = Container::Vertical(); | ||||
|   Input input_1; | ||||
|   Input input_2; | ||||
|   Input input_3; | ||||
|   std::wstring first_name_; | ||||
|   std::wstring last_name_; | ||||
|   std::wstring first_name_placeholder_ = L"first_name"; | ||||
|   std::wstring last_name_placeholder_ = L"last_name"; | ||||
|   Component input_first_name_ = Input(&first_name_, &first_name_placeholder_); | ||||
|   Component input_last_name_ = Input(&last_name_, &last_name_placeholder_); | ||||
|  | ||||
|   Element Render() override { | ||||
|     return border(vbox({ | ||||
|         hbox({text(L" input_1 : "), input_1.Render()}), | ||||
|         hbox({text(L" input_2 : "), input_2.Render()}), | ||||
|         hbox({text(L" input_3 : "), input_3.Render()}), | ||||
|         text(L"Hello " + first_name_ + L" " + last_name_), | ||||
|         separator(), | ||||
|         hbox({text(L" First name  : "), input_first_name_->Render()}), | ||||
|         hbox({text(L" Last name   : "), input_last_name_->Render()}), | ||||
|     })); | ||||
|   } | ||||
|  | ||||
|  public: | ||||
|   MyComponent() { | ||||
|     Add(Container::Vertical({ | ||||
|         input_first_name_, | ||||
|         input_last_name_, | ||||
|     })); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   auto screen = ScreenInteractive::TerminalOutput(); | ||||
|   MyComponent component; | ||||
|   component.on_enter = screen.ExitLoopClosure(); | ||||
|   screen.Loop(&component); | ||||
|   screen.Loop(Make<MyComponent>()); | ||||
| } | ||||
|  | ||||
| // Copyright 2020 Arthur Sonzogni. All rights reserved. | ||||
|   | ||||
| @@ -1,24 +1,30 @@ | ||||
| #include <functional>  // for function | ||||
| #include <iostream>    // for basic_ostream::ope... | ||||
| #include <string>      // for wstring, allocator | ||||
| #include <iostream>  // for basic_ostream::operator<<, operator<<, endl, basic_ostream, basic_ostream<>::__ostream_type, cout, ostream | ||||
| #include <string>    // for wstring, allocator, basic_string | ||||
| #include <vector>    // for vector | ||||
|  | ||||
| #include "ftxui/component/menu.hpp"                // for Menu | ||||
| #include "ftxui/component/captured_mouse.hpp"      // for ftxui | ||||
| #include "ftxui/component/component.hpp"           // for Menu | ||||
| #include "ftxui/component/menu.hpp"                // for MenuBase | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for ScreenInteractive | ||||
| #include "ftxui/screen/box.hpp"                    // for ftxui | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   using namespace ftxui; | ||||
|   auto screen = ScreenInteractive::TerminalOutput(); | ||||
|  | ||||
|   Menu menu; | ||||
|   menu.entries = {L"entry 1", L"entry 2", L"entry 3"}; | ||||
|   menu.selected = 0; | ||||
|   menu.on_enter = screen.ExitLoopClosure(); | ||||
|   std::vector<std::wstring> entries = { | ||||
|       L"entry 1", | ||||
|       L"entry 2", | ||||
|       L"entry 3", | ||||
|   }; | ||||
|   int selected = 0; | ||||
|  | ||||
|   screen.Loop(&menu); | ||||
|   auto menu = Menu(&entries, &selected); | ||||
|   MenuBase::From(menu)->on_enter = screen.ExitLoopClosure(); | ||||
|  | ||||
|   std::cout << "Selected element = " << menu.selected << std::endl; | ||||
|   screen.Loop(menu); | ||||
|  | ||||
|   std::cout << "Selected element = " << selected << std::endl; | ||||
| } | ||||
|  | ||||
| // Copyright 2020 Arthur Sonzogni. All rights reserved. | ||||
|   | ||||
| @@ -1,62 +1,57 @@ | ||||
| #include <functional>  // for function | ||||
| #include <string>      // for wstring, allocator | ||||
| #include <memory>      // for __shared_ptr_access, shared_ptr | ||||
| #include <string>  // for wstring, allocator, operator+, to_string, basic_string | ||||
| #include <vector>  // for vector | ||||
|  | ||||
| #include "ftxui/component/component.hpp"           // for Component | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for ftxui | ||||
| #include "ftxui/component/component.hpp"       // for Menu, Make | ||||
| #include "ftxui/component/component_base.hpp"  // for ComponentBase | ||||
| #include "ftxui/component/container.hpp"       // for Container | ||||
| #include "ftxui/component/menu.hpp"                // for Menu | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for ScreenInteractive | ||||
| #include "ftxui/dom/elements.hpp"                  // for text, separator, bold | ||||
| #include "ftxui/screen/box.hpp"                    // for ftxui | ||||
| #include "ftxui/component/menu.hpp"            // for MenuBase | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for Component, ScreenInteractive | ||||
| #include "ftxui/dom/elements.hpp"  // for text, separator, bold, hcenter, vbox, hbox, gauge, Element, operator|, border | ||||
| #include "ftxui/screen/string.hpp"  // for to_wstring | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| class MyComponent : public Component { | ||||
|  public: | ||||
|   MyComponent() { | ||||
|     Add(&container); | ||||
|     container.Add(&left_menu); | ||||
|     container.Add(&right_menu); | ||||
|  | ||||
|     left_menu.entries = { | ||||
| class MyComponent : public ComponentBase { | ||||
|  private: | ||||
|   std::vector<std::wstring> 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 = { | ||||
|   std::vector<std::wstring> right_menu_entries = { | ||||
|       L"0%", L"1%", L"2%", L"3%", L"4%",  L"5%", | ||||
|       L"6%", L"7%", L"8%", L"9%", L"10%", | ||||
|   }; | ||||
|  | ||||
|     left_menu.on_enter = [this]() { on_enter(); }; | ||||
|     right_menu.on_enter = [this]() { on_enter(); }; | ||||
|   } | ||||
|  | ||||
|   std::function<void()> on_enter = []() {}; | ||||
|  | ||||
|  private: | ||||
|   Container container = Container::Horizontal(); | ||||
|   Menu left_menu; | ||||
|   Menu right_menu; | ||||
|   int left_menu_selected = 0; | ||||
|   int right_menu_selected = 0; | ||||
|   Component left_menu_ = Menu(&left_menu_entries, &left_menu_selected); | ||||
|   Component right_menu_ = Menu(&right_menu_entries, &right_menu_selected); | ||||
|   Component container = Container::Horizontal({ | ||||
|       left_menu_, | ||||
|       right_menu_, | ||||
|   }); | ||||
|  | ||||
|   Element Render() override { | ||||
|     int sum = left_menu.selected * 10 + right_menu.selected; | ||||
|     return border(vbox({ | ||||
|     int sum = left_menu_selected * 10 + right_menu_selected; | ||||
|     return vbox({ | ||||
|                // -------- Top panel -------------- | ||||
|                hbox({ | ||||
|                    // -------- Left Menu -------------- | ||||
|                    vbox({ | ||||
|                        hcenter(bold(text(L"Percentage by 10%"))), | ||||
|                        separator(), | ||||
|                 left_menu.Render(), | ||||
|             }) | flex, | ||||
|                        left_menu_->Render(), | ||||
|                    }), | ||||
|                    separator(), | ||||
|                    // -------- Right Menu -------------- | ||||
|                    vbox({ | ||||
|                        hcenter(bold(text(L"Percentage by 1%"))), | ||||
|                        separator(), | ||||
|                 right_menu.Render(), | ||||
|             }) | flex, | ||||
|             filler(), | ||||
|                        right_menu_->Render(), | ||||
|                    }), | ||||
|                    separator(), | ||||
|                }), | ||||
|                separator(), | ||||
|                // -------- Bottom panel -------------- | ||||
| @@ -69,16 +64,25 @@ class MyComponent : public Component { | ||||
|                        text(L"  text : "), | ||||
|                        text(to_wstring(std::to_string(sum) + " %")), | ||||
|                    }), | ||||
|         }) | flex, | ||||
|     })); | ||||
|                }), | ||||
|            }) | | ||||
|            border; | ||||
|   } | ||||
|  | ||||
|  public: | ||||
|   MyComponent() { | ||||
|     Add(container); | ||||
|     MenuBase::From(left_menu_)->on_enter = [this]() { on_enter(); }; | ||||
|     MenuBase::From(right_menu_)->on_enter = [this]() { on_enter(); }; | ||||
|   } | ||||
|   std::function<void()> on_enter = []() {}; | ||||
| }; | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   auto screen = ScreenInteractive::TerminalOutput(); | ||||
|   MyComponent component; | ||||
|   component.on_enter = screen.ExitLoopClosure(); | ||||
|   screen.Loop(&component); | ||||
|   auto component = Make<MyComponent>(); | ||||
|   component->on_enter = screen.ExitLoopClosure(); | ||||
|   screen.Loop(component); | ||||
| } | ||||
|  | ||||
| // Copyright 2020 Arthur Sonzogni. All rights reserved. | ||||
|   | ||||
| @@ -1,82 +1,92 @@ | ||||
| #include <functional>        // for function | ||||
| #include <initializer_list>  // for initializer_list | ||||
| #include <string>            // for wstring, allocator | ||||
| #include <memory>            // for __shared_ptr_access | ||||
| #include <string>            // for wstring, allocator, basic_string | ||||
| #include <vector>            // for vector | ||||
|  | ||||
| #include "ftxui/component/component.hpp"           // for Component | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for ftxui | ||||
| #include "ftxui/component/component.hpp"       // for Menu, Make | ||||
| #include "ftxui/component/component_base.hpp"  // for ComponentBase | ||||
| #include "ftxui/component/container.hpp"       // for Container | ||||
| #include "ftxui/component/menu.hpp"                // for Menu | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for ScreenInteractive | ||||
| #include "ftxui/dom/elements.hpp"                  // for operator|, Element | ||||
| #include "ftxui/screen/box.hpp"                    // for ftxui | ||||
| #include "ftxui/screen/color.hpp"                  // for Color, Color::Blue | ||||
| #include "ftxui/component/menu.hpp"            // for MenuBase | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for Component, ScreenInteractive | ||||
| #include "ftxui/dom/elements.hpp"  // for operator|, Element, separator, bgcolor, color, flex, Decorator, bold, hbox, border, dim | ||||
| #include "ftxui/screen/color.hpp"  // for Color, Color::Blue, Color::BlueLight, Color::Red, Color::Yellow | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| class MyComponent : public Component { | ||||
|  public: | ||||
|   MyComponent() { | ||||
|     Add(&container); | ||||
|  | ||||
|     for (Menu* menu : { | ||||
|              &menu_1, | ||||
|              &menu_2, | ||||
|              &menu_3, | ||||
|              &menu_4, | ||||
|              &menu_5, | ||||
|              &menu_6, | ||||
|          }) { | ||||
|       container.Add(menu); | ||||
|       menu->entries = { | ||||
| std::vector<std::wstring> entries = { | ||||
|     L"Monkey", L"Dog", L"Cat", L"Bird", L"Elephant", | ||||
|       }; | ||||
|       menu->on_enter = [this]() { on_enter(); }; | ||||
| }; | ||||
|  | ||||
| class MyComponent : public ComponentBase { | ||||
|  public: | ||||
|   MyComponent(std::function<void(void)> exit) { | ||||
|     on_enter_ = exit; | ||||
|  | ||||
|     Add(container); | ||||
|  | ||||
|     for (Component menu : | ||||
|          {menu_1_, menu_2_, menu_3_, menu_4_, menu_5_, menu_6_}) | ||||
|       MenuBase::From(menu)->on_enter = [this] { on_enter_(); }; | ||||
|  | ||||
|     MenuBase::From(menu_2_)->focused_style = bold | color(Color::Blue); | ||||
|     MenuBase::From(menu_2_)->selected_style = color(Color::Blue); | ||||
|     MenuBase::From(menu_2_)->selected_focused_style = bold | color(Color::Blue); | ||||
|  | ||||
|     MenuBase::From(menu_3_)->selected_style = color(Color::Blue); | ||||
|     MenuBase::From(menu_3_)->focused_style = bgcolor(Color::Blue); | ||||
|     MenuBase::From(menu_3_)->selected_focused_style = bgcolor(Color::Blue); | ||||
|  | ||||
|     MenuBase::From(menu_4_)->selected_style = bgcolor(Color::Blue); | ||||
|     MenuBase::From(menu_4_)->focused_style = bgcolor(Color::BlueLight); | ||||
|     MenuBase::From(menu_4_)->selected_focused_style = bgcolor(Color::BlueLight); | ||||
|  | ||||
|     MenuBase::From(menu_5_)->normal_style = bgcolor(Color::Blue); | ||||
|     MenuBase::From(menu_5_)->selected_style = bgcolor(Color::Yellow); | ||||
|     MenuBase::From(menu_5_)->focused_style = bgcolor(Color::Red); | ||||
|     MenuBase::From(menu_5_)->selected_focused_style = bgcolor(Color::Red); | ||||
|  | ||||
|     MenuBase::From(menu_6_)->normal_style = dim | color(Color::Blue); | ||||
|     MenuBase::From(menu_6_)->selected_style = color(Color::Blue); | ||||
|     MenuBase::From(menu_6_)->focused_style = bold | color(Color::Blue); | ||||
|     MenuBase::From(menu_6_)->selected_focused_style = bold | color(Color::Blue); | ||||
|   } | ||||
|  | ||||
|     menu_2.focused_style = bold | color(Color::Blue); | ||||
|     menu_2.selected_style = color(Color::Blue); | ||||
|     menu_2.selected_focused_style = bold | color(Color::Blue); | ||||
|  | ||||
|     menu_3.selected_style = color(Color::Blue); | ||||
|     menu_3.focused_style = bgcolor(Color::Blue); | ||||
|     menu_3.selected_focused_style = bgcolor(Color::Blue); | ||||
|  | ||||
|     menu_4.selected_style = bgcolor(Color::Blue); | ||||
|     menu_4.focused_style = bgcolor(Color::BlueLight); | ||||
|     menu_4.selected_focused_style = bgcolor(Color::BlueLight); | ||||
|  | ||||
|     menu_5.normal_style = bgcolor(Color::Blue); | ||||
|     menu_5.selected_style = bgcolor(Color::Yellow); | ||||
|     menu_5.focused_style = bgcolor(Color::Red); | ||||
|     menu_5.selected_focused_style = bgcolor(Color::Red); | ||||
|  | ||||
|     menu_6.normal_style = dim | color(Color::Blue); | ||||
|     menu_6.selected_style = color(Color::Blue); | ||||
|     menu_6.focused_style = bold | color(Color::Blue); | ||||
|     menu_6.selected_focused_style = bold | color(Color::Blue); | ||||
|   } | ||||
|  | ||||
|   std::function<void()> on_enter = []() {}; | ||||
|   std::function<void()> on_enter_; | ||||
|  | ||||
|  private: | ||||
|   Container container = Container::Horizontal(); | ||||
|   Menu menu_1; | ||||
|   Menu menu_2; | ||||
|   Menu menu_3; | ||||
|   Menu menu_4; | ||||
|   Menu menu_5; | ||||
|   Menu menu_6; | ||||
|   int menu_1_selected_ = 0; | ||||
|   int menu_2_selected_ = 0; | ||||
|   int menu_3_selected_ = 0; | ||||
|   int menu_4_selected_ = 0; | ||||
|   int menu_5_selected_ = 0; | ||||
|   int menu_6_selected_ = 0; | ||||
|   Component menu_1_ = Menu(&entries, &menu_1_selected_); | ||||
|   Component menu_2_ = Menu(&entries, &menu_2_selected_); | ||||
|   Component menu_3_ = Menu(&entries, &menu_3_selected_); | ||||
|   Component menu_4_ = Menu(&entries, &menu_4_selected_); | ||||
|   Component menu_5_ = Menu(&entries, &menu_5_selected_); | ||||
|   Component menu_6_ = Menu(&entries, &menu_6_selected_); | ||||
|   Component container = Container::Horizontal({ | ||||
|       menu_1_, | ||||
|       menu_2_, | ||||
|       menu_3_, | ||||
|       menu_4_, | ||||
|       menu_5_, | ||||
|       menu_6_, | ||||
|   }); | ||||
|  | ||||
|   // clang-format off | ||||
|   Element Render() override { | ||||
|    return | ||||
|       hbox({ | ||||
|           menu_1.Render() | flex, separator(), | ||||
|           menu_2.Render() | flex, separator(), | ||||
|           menu_3.Render() | flex, separator(), | ||||
|           menu_4.Render() | flex, separator(), | ||||
|           menu_5.Render() | flex, separator(), | ||||
|           menu_6.Render() | flex, | ||||
|         menu_1_->Render() | flex, separator(), | ||||
|         menu_2_->Render() | flex, separator(), | ||||
|         menu_3_->Render() | flex, separator(), | ||||
|         menu_4_->Render() | flex, separator(), | ||||
|         menu_5_->Render() | flex, separator(), | ||||
|         menu_6_->Render() | flex, | ||||
|       }) | border; | ||||
|   } | ||||
|   // clang-format on | ||||
| @@ -84,9 +94,7 @@ class MyComponent : public Component { | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   auto screen = ScreenInteractive::TerminalOutput(); | ||||
|   MyComponent component; | ||||
|   component.on_enter = screen.ExitLoopClosure(); | ||||
|   screen.Loop(&component); | ||||
|   screen.Loop(Make<MyComponent>(screen.ExitLoopClosure())); | ||||
| } | ||||
|  | ||||
| // Copyright 2020 Arthur Sonzogni. All rights reserved. | ||||
|   | ||||
| @@ -1,132 +1,130 @@ | ||||
| #include <functional>  // for function | ||||
| #include <memory>      // for allocator_traits<>... | ||||
| #include <string>      // for operator+, wstring | ||||
| #include <memory>  // for allocator, __shared_ptr_access, shared_ptr, make_shared | ||||
| #include <string>  // for wstring, operator+, basic_string, char_traits | ||||
| #include <vector>  // for vector | ||||
|  | ||||
| #include "ftxui/component/button.hpp"              // for Button | ||||
| #include "ftxui/component/component.hpp"           // for Component | ||||
| #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 Element, operator| | ||||
| #include "ftxui/screen/box.hpp"                    // for ftxui | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for Component, ScreenInteractive | ||||
| #include "ftxui/dom/elements.hpp"  // for Element, operator|, filler, text, hbox, separator, center, vbox, bold, border, clear_under, dbox, size, GREATER_THAN, HEIGHT | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| // The main screen, at depth 0. It display the main content. | ||||
| class Content : public Component { | ||||
|  public: | ||||
|   std::function<void()> on_rate_ftxui = [] {}; | ||||
|   std::function<void()> on_quit = [] {}; | ||||
|   std::wstring rating_ = L"3/5 stars"; | ||||
|   Content() { | ||||
|     Add(&container_); | ||||
|     container_.Add(&button_rate_ftxui); | ||||
|     container_.Add(&button_quit_); | ||||
|     button_rate_ftxui.on_click = [&] { on_rate_ftxui(); }; | ||||
|     button_quit_.on_click = [&] { on_quit(); }; | ||||
|   } | ||||
| class Content : public ComponentBase { | ||||
|  private: | ||||
|   std::wstring label_rate_ftxui_ = L"Rate FTXUI"; | ||||
|   std::wstring label_quit_ = L"Quit"; | ||||
|   bool modal_open_ = false; | ||||
|  | ||||
|   Element Render() final { | ||||
|     auto button_elements = hbox({ | ||||
|         button_rate_ftxui.Render(), | ||||
|         filler(), | ||||
|         button_quit_.Render(), | ||||
|   Component button_rate_ftxui_ = | ||||
|       Button(&label_rate_ftxui_, [this] { on_rate_ftxui(); }); | ||||
|   Component button_quit_ = Button(&label_quit_, [this] { on_quit(); }); | ||||
|   Component container_ = Container::Horizontal({ | ||||
|       button_rate_ftxui_, | ||||
|       button_quit_, | ||||
|   }); | ||||
|  | ||||
|  public: | ||||
|   std::wstring rating = L"3/5 stars"; | ||||
|   std::function<void()> on_rate_ftxui; | ||||
|   std::function<void()> on_quit; | ||||
|  | ||||
|   Content() { Add(container_); } | ||||
|  | ||||
|   Element Render() final { | ||||
|     auto document =  // | ||||
|         vbox({ | ||||
|             text(L"Modal dialog example"), | ||||
|             separator(), | ||||
|             text(L"☆☆☆ FTXUI:" + rating_ + L" ☆☆☆") | bold, | ||||
|             text(L"☆☆☆ FTXUI:" + rating + L" ☆☆☆") | bold, | ||||
|             filler(), | ||||
|             button_elements, | ||||
|             hbox({ | ||||
|                 button_rate_ftxui_->Render(), | ||||
|                 filler(), | ||||
|                 button_quit_->Render(), | ||||
|             }), | ||||
|         }) | | ||||
|         border; | ||||
|  | ||||
|     return document | size(HEIGHT, GREATER_THAN, 18) | center; | ||||
|   } | ||||
| }; | ||||
|  | ||||
|  private: | ||||
|   Container container_ = Container::Horizontal(); | ||||
|   Button button_rate_ftxui = Button(L"Rate FTXUI"); | ||||
|   Button button_quit_ = Button(L"Quit"); | ||||
| std::vector<std::wstring> rating_labels = { | ||||
|     L"1/5 stars", L"2/5 stars", L"3/5 stars", L"4/5 stars", L"5/5 stars", | ||||
| }; | ||||
|  | ||||
| // The "modal" screen, at depth 1. It display the modal dialog. | ||||
| class Modal : public Component { | ||||
| class Modal : public ComponentBase { | ||||
|  private: | ||||
|   Component container_ = Container::Horizontal({ | ||||
|       Button(&rating_labels[0], [this] { on_click(rating_labels[0]); }), | ||||
|       Button(&rating_labels[1], [this] { on_click(rating_labels[1]); }), | ||||
|       Button(&rating_labels[2], [this] { on_click(rating_labels[2]); }), | ||||
|       Button(&rating_labels[3], [this] { on_click(rating_labels[3]); }), | ||||
|       Button(&rating_labels[4], [this] { on_click(rating_labels[4]); }), | ||||
|   }); | ||||
|  | ||||
|  public: | ||||
|   std::function<void(std::wstring)> on_click; | ||||
|  | ||||
|   Modal() { | ||||
|     Add(&container_); | ||||
|     buttons_.resize(5); | ||||
|     for (int i = 0; i < 5; ++i) { | ||||
|       std::wstring stars = std::to_wstring(i + 1) + L"/5 stars"; | ||||
|       buttons_[i] = Button(stars); | ||||
|       buttons_[i].on_click = [&, stars] { on_click(stars); }; | ||||
|       container_.Add(&buttons_[i]); | ||||
|     } | ||||
|   } | ||||
|   Modal() { Add(container_); } | ||||
|  | ||||
|   Element Render() final { | ||||
|     return vbox({ | ||||
|                text(L"Do you like FTXUI?"), | ||||
|                separator(), | ||||
|                hbox({ | ||||
|                    buttons_[0].Render(), | ||||
|                    buttons_[1].Render(), | ||||
|                    buttons_[2].Render(), | ||||
|                    buttons_[3].Render(), | ||||
|                    buttons_[4].Render(), | ||||
|                }), | ||||
|                hbox(container_->Render()), | ||||
|            }) | | ||||
|            border; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   Container container_ = Container::Horizontal(); | ||||
|   std::vector<Button> buttons_; | ||||
| }; | ||||
|  | ||||
| class MyComponent : public Component { | ||||
| class MyComponent : public ComponentBase { | ||||
|  private: | ||||
|   std::shared_ptr<Content> content_ = std::make_shared<Content>(); | ||||
|   std::shared_ptr<Modal> modal_ = std::make_shared<Modal>(); | ||||
|  | ||||
|   int depth = 0; | ||||
|   Component container_ = Container::Tab(&depth, | ||||
|                                         { | ||||
|                                             content_, | ||||
|                                             modal_, | ||||
|                                         }); | ||||
|  | ||||
|   std::function<void()> on_quit_; | ||||
|  | ||||
|  public: | ||||
|   std::function<void()> on_quit = [] {}; | ||||
|   MyComponent(std::function<void()> on_quit) : on_quit_(on_quit) { | ||||
|     Add(container_); | ||||
|  | ||||
|   MyComponent() { | ||||
|     Add(&container_); | ||||
|     container_.Add(&content_); | ||||
|     container_.Add(&modal_); | ||||
|  | ||||
|     content_.on_quit = [&] { on_quit(); }; | ||||
|     content_.on_rate_ftxui = [&] { modal_.TakeFocus(); }; | ||||
|     modal_.on_click = [&](std::wstring rating) { | ||||
|       content_.rating_ = rating; | ||||
|       content_.TakeFocus(); | ||||
|     content_->on_quit = [&] { on_quit(); }; | ||||
|     content_->on_rate_ftxui = [this] { depth = 1; }; | ||||
|     modal_->on_click = [&](std::wstring rating) { | ||||
|       content_->rating = rating; | ||||
|       depth = 0; | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   Element Render() final { | ||||
|     Element document = content_.Render(); | ||||
|     if (modal_.Focused()) { | ||||
|     Element document = content_->Render(); | ||||
|  | ||||
|     if (depth == 1) { | ||||
|       document = dbox({ | ||||
|           document, | ||||
|           modal_.Render() | clear_under | center, | ||||
|           modal_->Render() | clear_under | center, | ||||
|       }); | ||||
|     } | ||||
|     return document; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   Container container_ = Container::Tab(nullptr); | ||||
|   Content content_; | ||||
|   Modal modal_; | ||||
| }; | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   auto screen = ScreenInteractive::TerminalOutput(); | ||||
|   MyComponent my_component; | ||||
|   my_component.on_quit = screen.ExitLoopClosure(); | ||||
|   screen.Loop(&my_component); | ||||
|   screen.Loop(Make<MyComponent>(screen.ExitLoopClosure())); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,18 +1,23 @@ | ||||
| #include "ftxui/component/radiobox.hpp" | ||||
| #include <string>  // for wstring, allocator, basic_string | ||||
| #include <vector>  // for vector | ||||
|  | ||||
| #include "ftxui/component/captured_mouse.hpp"      // for ftxui | ||||
| #include "ftxui/component/component.hpp"           // for Radiobox | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for ScreenInteractive | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   auto screen = ScreenInteractive::TerminalOutput(); | ||||
|   RadioBox radiobox; | ||||
|   radiobox.entries = { | ||||
|   std::vector<std::wstring> radiobox_list = { | ||||
|       L"Use gcc", | ||||
|       L"Use clang", | ||||
|       L"Use emscripten", | ||||
|       L"Use tcc", | ||||
|   }; | ||||
|   screen.Loop(&radiobox); | ||||
|   int selected = 0; | ||||
|  | ||||
|   auto screen = ScreenInteractive::TerminalOutput(); | ||||
|   screen.Loop(Radiobox(&radiobox_list, &selected)); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,35 +1,36 @@ | ||||
| #include <string>  // for wstring, operator+ | ||||
| #include <vector>  // for vector | ||||
|  | ||||
| #include "ftxui/component/component.hpp"           // for Component | ||||
| #include "ftxui/component/radiobox.hpp"            // for RadioBox | ||||
| #include "ftxui/component/captured_mouse.hpp"      // for ftxui | ||||
| #include "ftxui/component/component.hpp"           // for Make, Radiobox | ||||
| #include "ftxui/component/component_base.hpp"      // for ComponentBase | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for ScreenInteractive | ||||
| #include "ftxui/dom/elements.hpp"                  // for Element, operator| | ||||
| #include "ftxui/screen/box.hpp"                    // for ftxui | ||||
| #include "ftxui/dom/elements.hpp"  // for Element, operator|, size, border, frame, HEIGHT, LESS_THAN | ||||
| #include "ftxui/screen/string.hpp"  // for to_wstring | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| class MyComponent : public Component { | ||||
|   RadioBox radiobox; | ||||
| class MyComponent : public ComponentBase { | ||||
|  private: | ||||
|   std::vector<std::wstring> entries_; | ||||
|   int selected_ = 0; | ||||
|  | ||||
|  public: | ||||
|   MyComponent() { | ||||
|     for (int i = 0; i < 30; ++i) { | ||||
|       radiobox.entries.push_back(L"RadioBox " + to_wstring(i)); | ||||
|     } | ||||
|     Add(&radiobox); | ||||
|     for (int i = 0; i < 30; ++i) | ||||
|       entries_.push_back(L"RadioBox " + to_wstring(i)); | ||||
|     Add(Radiobox(&entries_, &selected_)); | ||||
|   } | ||||
|  | ||||
|   Element Render() override { | ||||
|     return radiobox.Render() | frame | size(HEIGHT, LESS_THAN, 10) | border; | ||||
|     return ComponentBase::Render() | frame | size(HEIGHT, LESS_THAN, 10) | | ||||
|            border; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   auto screen = ScreenInteractive::FitComponent(); | ||||
|   MyComponent component; | ||||
|   screen.Loop(&component); | ||||
|   screen.Loop(Make<MyComponent>()); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|   | ||||
| @@ -1,82 +1,16 @@ | ||||
| #include <functional>  // for function | ||||
| #include <memory>      // for allocator, unique_ptr | ||||
| #include <string>      // for operator+, to_wstring | ||||
| #include <memory>  // for allocator | ||||
|  | ||||
| #include "ftxui/component/component.hpp"           // for Component, Compone... | ||||
| #include "ftxui/component/container.hpp"           // for Container | ||||
| #include "ftxui/component/event.hpp"               // for Event, Event::Escape | ||||
| #include "ftxui/component/captured_mouse.hpp"      // for ftxui | ||||
| #include "ftxui/component/component.hpp"           // for Slider | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for ScreenInteractive | ||||
| #include "ftxui/component/slider.hpp"              // for Slider | ||||
| #include "ftxui/dom/elements.hpp"                  // for separator, operator| | ||||
| #include "ftxui/screen/box.hpp"                    // for ftxui | ||||
| #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 Component { | ||||
|  public: | ||||
|   MyComponent(int* red, int* green, int* blue, std::function<void(void)> quit) | ||||
|       : red_(red), green_(green), blue_(blue), quit_(quit) { | ||||
|     Add(&container_); | ||||
|     container_.Add(slider_red_.get()); | ||||
|     container_.Add(slider_green_.get()); | ||||
|     container_.Add(slider_blue_.get()); | ||||
|   } | ||||
|  | ||||
|   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 Component::OnEvent(event); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   int* red_; | ||||
|   int* green_; | ||||
|   int* blue_; | ||||
|   Container container_ = Container::Vertical(); | ||||
|   ComponentPtr slider_red_ = Slider(L"Red  :", red_, 0, 255, 1); | ||||
|   ComponentPtr slider_green_ = Slider(L"Green:", green_, 0, 255, 1); | ||||
|   ComponentPtr slider_blue_ = Slider(L"Blue :", blue_, 0, 255, 1); | ||||
|   std::function<void(void)> quit_; | ||||
| }; | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   auto screen = ScreenInteractive::TerminalOutput(); | ||||
|   int red = 128; | ||||
|   int green = 25; | ||||
|   int blue = 100; | ||||
|   auto component = MyComponent(&red, &green, &blue, screen.ExitLoopClosure()); | ||||
|   screen.Loop(&component); | ||||
|   int value = 50; | ||||
|   auto slider = Slider(L"Value:", &value, 0, 100, 1); | ||||
|   screen.Loop(slider); | ||||
| } | ||||
|  | ||||
| // Copyright 2020 Arthur Sonzogni. All rights reserved. | ||||
|   | ||||
| @@ -1,71 +1,77 @@ | ||||
| #include <functional>  // for function | ||||
| #include <string>      // for wstring, allocator | ||||
| #include <memory>  // for __shared_ptr_access | ||||
| #include <string>  // for wstring, allocator, basic_string | ||||
| #include <vector>  // for vector | ||||
|  | ||||
| #include "ftxui/component/component.hpp"           // for Component | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for ftxui | ||||
| #include "ftxui/component/component.hpp"       // for Radiobox, Make, Toggle | ||||
| #include "ftxui/component/component_base.hpp"  // for ComponentBase | ||||
| #include "ftxui/component/container.hpp"       // for Container | ||||
| #include "ftxui/component/radiobox.hpp"            // for RadioBox | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for ScreenInteractive | ||||
| #include "ftxui/component/toggle.hpp"              // for Toggle | ||||
| #include "ftxui/dom/elements.hpp"                  // for Element, operator| | ||||
| #include "ftxui/screen/box.hpp"                    // for ftxui | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for Component, ScreenInteractive | ||||
| #include "ftxui/dom/elements.hpp"  // for Element, separator, operator|, vbox, border | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| class MyComponent : public Component { | ||||
|  public: | ||||
|   MyComponent() { | ||||
|     Add(&container_); | ||||
|     container_.Add(&toggle_); | ||||
|  | ||||
|     toggle_.entries = { | ||||
| class MyComponent : public ComponentBase { | ||||
|  private: | ||||
|   std::vector<std::wstring> tab_values_ = { | ||||
|       L"tab_1", | ||||
|       L"tab_2", | ||||
|       L"tab_3", | ||||
|   }; | ||||
|   int tab_selected_ = 0; | ||||
|   Component tab_toggle_ = Toggle(&tab_values_, &tab_selected_); | ||||
|  | ||||
|     container_.Add(&tab_container_); | ||||
|   std::vector<std::wstring> tab_1_entries_ = { | ||||
|       L"Forest", | ||||
|       L"Water", | ||||
|       L"I don't know", | ||||
|   }; | ||||
|   int tab_1_selected_ = 0; | ||||
|  | ||||
|     radiobox_1_.entries = {L"Forest", L"Water", L"I don't know"}; | ||||
|     tab_container_.Add(&radiobox_1_); | ||||
|  | ||||
|     radiobox_2_.entries = { | ||||
|   std::vector<std::wstring> tab_2_entries_ = { | ||||
|       L"Hello", | ||||
|       L"Hi", | ||||
|       L"Hay", | ||||
|   }; | ||||
|     tab_container_.Add(&radiobox_2_); | ||||
|   int tab_2_selected_ = 0; | ||||
|  | ||||
|     radiobox_3_.entries = { | ||||
|   std::vector<std::wstring> tab_3_entries_ = { | ||||
|       L"Table", | ||||
|       L"Nothing", | ||||
|       L"Is", | ||||
|       L"Empty", | ||||
|   }; | ||||
|     tab_container_.Add(&radiobox_3_); | ||||
|   } | ||||
|   int tab_3_selected_ = 0; | ||||
|  | ||||
|   std::function<void()> on_enter = []() {}; | ||||
|   Component tab_container_ = | ||||
|       Container::Tab(&tab_selected_, | ||||
|                      { | ||||
|                          Radiobox(&tab_1_entries_, &tab_1_selected_), | ||||
|                          Radiobox(&tab_2_entries_, &tab_2_selected_), | ||||
|                          Radiobox(&tab_3_entries_, &tab_3_selected_), | ||||
|                      }); | ||||
|  | ||||
|   Component container_ = Container::Vertical({ | ||||
|       tab_toggle_, | ||||
|       tab_container_, | ||||
|   }); | ||||
|  | ||||
|  public: | ||||
|   MyComponent() { Add(container_); } | ||||
|  | ||||
|   Element Render() { | ||||
|     return vbox(toggle_.Render(), separator(), tab_container_.Render()) | | ||||
|     return vbox({ | ||||
|                tab_toggle_->Render(), | ||||
|                separator(), | ||||
|                tab_container_->Render(), | ||||
|            }) | | ||||
|            border; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   Toggle toggle_; | ||||
|   Container container_ = Container::Vertical(); | ||||
|   Container tab_container_ = Container::Tab(&(toggle_.selected)); | ||||
|   RadioBox radiobox_1_; | ||||
|   RadioBox radiobox_2_; | ||||
|   RadioBox radiobox_3_; | ||||
| }; | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   auto screen = ScreenInteractive::TerminalOutput(); | ||||
|   MyComponent component; | ||||
|   component.on_enter = screen.ExitLoopClosure(); | ||||
|   screen.Loop(&component); | ||||
|   screen.Loop(Make<MyComponent>()); | ||||
| } | ||||
|  | ||||
| // Copyright 2020 Arthur Sonzogni. All rights reserved. | ||||
|   | ||||
| @@ -1,64 +1,77 @@ | ||||
| #include <functional>  // for function | ||||
| #include <string>      // for wstring, allocator | ||||
| #include <memory>  // for __shared_ptr_access | ||||
| #include <string>  // for wstring, allocator, basic_string | ||||
| #include <vector>  // for vector | ||||
|  | ||||
| #include "ftxui/component/component.hpp"           // for Component | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for ftxui | ||||
| #include "ftxui/component/component.hpp"       // for Radiobox, Make, Menu | ||||
| #include "ftxui/component/component_base.hpp"  // for ComponentBase | ||||
| #include "ftxui/component/container.hpp"       // for Container | ||||
| #include "ftxui/component/menu.hpp"                // for Menu | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for ScreenInteractive | ||||
| #include "ftxui/screen/box.hpp"                    // for ftxui | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for Component, ScreenInteractive | ||||
| #include "ftxui/dom/elements.hpp"  // for Element, separator, hbox, operator|, border | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| class MyComponent : public Component { | ||||
|  public: | ||||
|   MyComponent() { | ||||
|     Add(&container_); | ||||
|     container_.Add(&menu_); | ||||
|  | ||||
|     menu_.entries = { | ||||
|         L"menu_1", | ||||
|         L"menu_2", | ||||
|         L"menu_3", | ||||
| class MyComponent : public ComponentBase { | ||||
|  private: | ||||
|   std::vector<std::wstring> tab_values_ = { | ||||
|       L"tab_1", | ||||
|       L"tab_2", | ||||
|       L"tab_3", | ||||
|   }; | ||||
|   int tab_selected_ = 0; | ||||
|   Component tab_toggle_ = Menu(&tab_values_, &tab_selected_); | ||||
|  | ||||
|     container_.Add(&tab_container_); | ||||
|   std::vector<std::wstring> tab_1_entries_ = { | ||||
|       L"Forest", | ||||
|       L"Water", | ||||
|       L"I don't know", | ||||
|   }; | ||||
|   int tab_1_selected_ = 0; | ||||
|  | ||||
|     menu_1_.entries = {L"Forest", L"Water", L"I don't know"}; | ||||
|     tab_container_.Add(&menu_1_); | ||||
|  | ||||
|     menu_2_.entries = { | ||||
|   std::vector<std::wstring> tab_2_entries_ = { | ||||
|       L"Hello", | ||||
|       L"Hi", | ||||
|       L"Hay", | ||||
|   }; | ||||
|     tab_container_.Add(&menu_2_); | ||||
|   int tab_2_selected_ = 0; | ||||
|  | ||||
|     menu_3_.entries = { | ||||
|   std::vector<std::wstring> tab_3_entries_ = { | ||||
|       L"Table", | ||||
|       L"Nothing", | ||||
|       L"Is", | ||||
|       L"Empty", | ||||
|   }; | ||||
|     tab_container_.Add(&menu_3_); | ||||
|   int tab_3_selected_ = 0; | ||||
|  | ||||
|   Component tab_container_ = | ||||
|       Container::Tab(&tab_selected_, | ||||
|                      { | ||||
|                          Radiobox(&tab_1_entries_, &tab_1_selected_), | ||||
|                          Radiobox(&tab_2_entries_, &tab_2_selected_), | ||||
|                          Radiobox(&tab_3_entries_, &tab_3_selected_), | ||||
|                      }); | ||||
|  | ||||
|   Component container_ = Container::Horizontal({ | ||||
|       tab_toggle_, | ||||
|       tab_container_, | ||||
|   }); | ||||
|  | ||||
|  public: | ||||
|   MyComponent() { Add(container_); } | ||||
|  | ||||
|   Element Render() { | ||||
|     return hbox({ | ||||
|                tab_toggle_->Render(), | ||||
|                separator(), | ||||
|                tab_container_->Render(), | ||||
|            }) | | ||||
|            border; | ||||
|   } | ||||
|  | ||||
|   std::function<void()> on_enter = []() {}; | ||||
|  | ||||
|  private: | ||||
|   Menu menu_; | ||||
|   Container container_ = Container::Horizontal(); | ||||
|   Container tab_container_ = Container::Tab(&(menu_.selected)); | ||||
|   Menu menu_1_; | ||||
|   Menu menu_2_; | ||||
|   Menu menu_3_; | ||||
| }; | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   auto screen = ScreenInteractive::TerminalOutput(); | ||||
|   MyComponent component; | ||||
|   component.on_enter = screen.ExitLoopClosure(); | ||||
|   screen.Loop(&component); | ||||
|   screen.Loop(Make<MyComponent>()); | ||||
| } | ||||
|  | ||||
| // Copyright 2020 Arthur Sonzogni. All rights reserved. | ||||
|   | ||||
| @@ -1,59 +1,82 @@ | ||||
| #include "ftxui/component/toggle.hpp" | ||||
| #include <functional>  // for function | ||||
| #include <memory>      // for allocator, __shared_ptr_access | ||||
| #include <string>      // for wstring, basic_string | ||||
| #include <vector>      // for vector | ||||
|  | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for ftxui | ||||
| #include "ftxui/component/component.hpp"       // for Toggle, Make | ||||
| #include "ftxui/component/component_base.hpp"  // for ComponentBase | ||||
| #include "ftxui/component/container.hpp"       // for Container | ||||
| #include "ftxui/component/event.hpp"           // for Event, Event::Return | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for ScreenInteractive | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for Component, ScreenInteractive | ||||
| #include "ftxui/dom/elements.hpp"  // for text, hbox, vbox, Element | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| class MyComponent : public Component { | ||||
|  public: | ||||
|   MyComponent() { | ||||
|     Add(&container_); | ||||
|     container_.Add(&toggle_1_); | ||||
|     container_.Add(&toggle_2_); | ||||
|     container_.Add(&toggle_3_); | ||||
|     container_.Add(&toggle_4_); | ||||
|  | ||||
|     toggle_1_.entries = {L"On", L"Off"}; | ||||
|     toggle_2_.entries = {L"Enabled", L"Disabled"}; | ||||
|     toggle_3_.entries = {L"10€", L"0€"}; | ||||
|     toggle_4_.entries = {L"Nothing", L"One element", L"Several elements"}; | ||||
|   } | ||||
|  | ||||
|   std::function<void()> on_enter = []() {}; | ||||
|  | ||||
| class MyComponent : public ComponentBase { | ||||
|  private: | ||||
|   Container container_ = Container::Vertical(); | ||||
|   Toggle toggle_1_; | ||||
|   Toggle toggle_2_; | ||||
|   Toggle toggle_3_; | ||||
|   Toggle toggle_4_; | ||||
|   std::vector<std::wstring> toggle_1_entries_ = { | ||||
|       L"On", | ||||
|       L"Off", | ||||
|   }; | ||||
|   std::vector<std::wstring> toggle_2_entries_ = { | ||||
|       L"Enabled", | ||||
|       L"Disabled", | ||||
|   }; | ||||
|   std::vector<std::wstring> toggle_3_entries_ = { | ||||
|       L"10€", | ||||
|       L"0€", | ||||
|   }; | ||||
|   std::vector<std::wstring> toggle_4_entries_ = { | ||||
|       L"Nothing", | ||||
|       L"One element", | ||||
|       L"Several elements", | ||||
|   }; | ||||
|  | ||||
|   int toggle_1_selected_ = 0; | ||||
|   int toggle_2_selected_ = 0; | ||||
|   int toggle_3_selected_ = 0; | ||||
|   int toggle_4_selected_ = 0; | ||||
|   Component toggle_1_ = Toggle(&toggle_1_entries_, &toggle_1_selected_); | ||||
|   Component toggle_2_ = Toggle(&toggle_2_entries_, &toggle_2_selected_); | ||||
|   Component toggle_3_ = Toggle(&toggle_3_entries_, &toggle_3_selected_); | ||||
|   Component toggle_4_ = Toggle(&toggle_4_entries_, &toggle_4_selected_); | ||||
|  | ||||
|   std::function<void()> exit_; | ||||
|  | ||||
|   Element Render() override { | ||||
|     return vbox({ | ||||
|         text(L"Choose your options:"), | ||||
|         text(L""), | ||||
|         hbox(text(L" * Poweroff on startup      : "), toggle_1_.Render()), | ||||
|         hbox(text(L" * Out of process           : "), toggle_2_.Render()), | ||||
|         hbox(text(L" * Price of the information : "), toggle_3_.Render()), | ||||
|         hbox(text(L" * Number of elements       : "), toggle_4_.Render()), | ||||
|         hbox(text(L" * Poweroff on startup      : "), toggle_1_->Render()), | ||||
|         hbox(text(L" * Out of process           : "), toggle_2_->Render()), | ||||
|         hbox(text(L" * Price of the information : "), toggle_3_->Render()), | ||||
|         hbox(text(L" * Number of elements       : "), toggle_4_->Render()), | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   bool OnEvent(Event event) override { | ||||
|     if (event == Event::Return) { | ||||
|       on_enter(); | ||||
|       exit_(); | ||||
|       return true; | ||||
|     } | ||||
|     return Component::OnEvent(event); | ||||
|     return ComponentBase::OnEvent(event); | ||||
|   } | ||||
|  | ||||
|  public: | ||||
|   MyComponent(std::function<void()> exit) : exit_(exit) { | ||||
|     Add(Container::Vertical({ | ||||
|         toggle_1_, | ||||
|         toggle_2_, | ||||
|         toggle_3_, | ||||
|         toggle_4_, | ||||
|     })); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   auto screen = ScreenInteractive::TerminalOutput(); | ||||
|   MyComponent component; | ||||
|   component.on_enter = screen.ExitLoopClosure(); | ||||
|   screen.Loop(&component); | ||||
|   screen.Loop(Make<MyComponent>(screen.ExitLoopClosure())); | ||||
| } | ||||
|  | ||||
| // Copyright 2020 Arthur Sonzogni. All rights reserved. | ||||
|   | ||||
| @@ -33,15 +33,18 @@ | ||||
|       "./component/menu.js", | ||||
|       "./component/menu2.js", | ||||
|       "./component/menu_style.js", | ||||
|       "./component/modal_dialog.js", | ||||
|       "./component/radiobox.js", | ||||
|       "./component/radiobox_in_frame.js", | ||||
|       "./component/slider.js", | ||||
|       "./component/tab_horizontal.js", | ||||
|       "./component/tab_vertical.js", | ||||
|       "./component/toggle.js", | ||||
|       "./component/modal_dialog.js", | ||||
|  | ||||
|       "./dom/border.js", | ||||
|       "./dom/color_gallery.js", | ||||
|       "./dom/color_info_palette256.js", | ||||
|       "./dom/color_truecolor_HSV.js", | ||||
|       "./dom/color_truecolor_RGB.js", | ||||
|       "./dom/dbox.js", | ||||
|       "./dom/gauge.js", | ||||
|       "./dom/graph.js", | ||||
| @@ -55,16 +58,12 @@ | ||||
|       "./dom/style_blink.js", | ||||
|       "./dom/style_bold.js", | ||||
|       "./dom/style_color.js", | ||||
|       "./dom/color_truecolor_RGB.js", | ||||
|       "./dom/color_truecolor_HSV.js", | ||||
|       "./dom/color_info_palette256.js", | ||||
|       "./dom/style_dim.js", | ||||
|       "./dom/style_gallery.js", | ||||
|       "./dom/style_inverted.js", | ||||
|       "./dom/style_underlined.js", | ||||
|       "./dom/vbox_hbox.js", | ||||
|       "./dom/window.js", | ||||
|  | ||||
|       "./util/print_key_press.js", | ||||
|     ]; | ||||
|  | ||||
|   | ||||
| @@ -4,16 +4,17 @@ | ||||
|  | ||||
| #include <stddef.h>                                // for size_t | ||||
| #include <algorithm>                               // for max | ||||
| #include <ftxui/component/component.hpp>           // for Component | ||||
| #include <ftxui/component/component.hpp>           // for Make | ||||
| #include <ftxui/component/screen_interactive.hpp>  // for ScreenInteractive | ||||
| #include <string>                                  // for allocator, operator+ | ||||
| #include <string>  // for allocator, operator+, wstring, char_traits, to_wstring, string | ||||
| #include <utility>  // for move | ||||
| #include <vector>   // for vector | ||||
|  | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for ftxui | ||||
| #include "ftxui/component/component_base.hpp"  // for ComponentBase | ||||
| #include "ftxui/component/event.hpp"           // for Event | ||||
| #include "ftxui/component/mouse.hpp"  // for Mouse, Mouse::Left | ||||
| #include "ftxui/dom/elements.hpp"     // for text, vbox, window | ||||
| #include "ftxui/screen/box.hpp"       // for ftxui | ||||
| #include "ftxui/component/mouse.hpp"  // for Mouse, Mouse::Left, Mouse::Middle, Mouse::None, Mouse::Pressed, Mouse::Released, Mouse::Right, Mouse::WheelDown, Mouse::WheelUp | ||||
| #include "ftxui/dom/elements.hpp"  // for text, vbox, window, Elements, Element | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| @@ -71,7 +72,7 @@ std::wstring Stringify(Event event) { | ||||
|   return out; | ||||
| } | ||||
|  | ||||
| class DrawKey : public Component { | ||||
| class DrawKey : public ComponentBase { | ||||
|  public: | ||||
|   ~DrawKey() override = default; | ||||
|  | ||||
| @@ -94,6 +95,5 @@ class DrawKey : public Component { | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   auto screen = ScreenInteractive::TerminalOutput(); | ||||
|   DrawKey draw_key; | ||||
|   screen.Loop(&draw_key); | ||||
|   screen.Loop(Make<DrawKey>()); | ||||
| } | ||||
|   | ||||
| @@ -1,36 +1,35 @@ | ||||
| #ifndef FTXUI_COMPONENT_BUTTON_HPP | ||||
| #define FTXUI_COMPONENT_BUTTON_HPP | ||||
|  | ||||
| #include <functional> | ||||
| #include <string> | ||||
| #include <functional>  // for function | ||||
| #include <string>      // for wstring | ||||
|  | ||||
| #include "ftxui/component/component.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/screen/box.hpp" | ||||
| #include "ftxui/component/component.hpp"       // for Component | ||||
| #include "ftxui/component/component_base.hpp"  // for ComponentBase | ||||
| #include "ftxui/dom/elements.hpp"              // for Element | ||||
| #include "ftxui/screen/box.hpp"                // for Box | ||||
|  | ||||
| namespace ftxui { | ||||
| struct Event; | ||||
|  | ||||
| /// @brief A button. An action is associated to the click event. | ||||
| /// @ingroup dom | ||||
| class Button : public Component { | ||||
| class ButtonBase : public ComponentBase { | ||||
|  public: | ||||
|   // Access this interface from a Component | ||||
|   static ButtonBase* From(Component); | ||||
|  | ||||
|   // Constructor. | ||||
|   Button() = default; | ||||
|   Button(std::wstring label) : label(label) {} | ||||
|   ~Button() override = default; | ||||
|  | ||||
|   /// The Button label. | ||||
|   std::wstring label = L"button"; | ||||
|  | ||||
|   /// Called when the user press the "enter" button. | ||||
|   std::function<void()> on_click = [] {}; | ||||
|   ButtonBase(const std::wstring* label, std::function<void()> on_click); | ||||
|   ~ButtonBase() override = default; | ||||
|  | ||||
|   // Component implementation. | ||||
|   Element Render() override; | ||||
|   bool OnEvent(Event) override; | ||||
|  | ||||
|  private: | ||||
|   const std::wstring* label_; | ||||
|   std::function<void()> on_click_; | ||||
|   Box box_; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,13 @@ | ||||
| #ifndef FTXUI_COMPONENT_CHECKBOX_HPP | ||||
| #define FTXUI_COMPONENT_CHECKBOX_HPP | ||||
|  | ||||
| #include <string> | ||||
| #include <functional>  // for function | ||||
| #include <string>      // for wstring, allocator | ||||
|  | ||||
| #include "ftxui/component/component.hpp" | ||||
| #include "ftxui/screen/box.hpp" | ||||
| #include "ftxui/component/component.hpp"       // for Component | ||||
| #include "ftxui/component/component_base.hpp"  // for ComponentBase | ||||
| #include "ftxui/dom/elements.hpp"  // for Element, Decorator, inverted, nothing | ||||
| #include "ftxui/screen/box.hpp"    // for Box | ||||
|  | ||||
| namespace ftxui { | ||||
| struct Event; | ||||
| @@ -12,14 +15,14 @@ struct Event; | ||||
| /// @brief A Checkbox. It can be checked or unchecked.Display an element on a | ||||
| /// ftxui::Screen. | ||||
| /// @ingroup dom | ||||
| class CheckBox : public Component { | ||||
| class CheckboxBase : public ComponentBase { | ||||
|  public: | ||||
|   // Constructor. | ||||
|   CheckBox() = default; | ||||
|   ~CheckBox() override = default; | ||||
|   // Access this interface from a Component | ||||
|   static CheckboxBase* From(Component component); | ||||
|  | ||||
|   bool state = false;  // The current state. true=checked, false:unchecked. | ||||
|   std::wstring label = L"label";  // The CheckBox label. | ||||
|   // Constructor. | ||||
|   CheckboxBase(const std::wstring* label, bool* state); | ||||
|   ~CheckboxBase() override = default; | ||||
|  | ||||
| #if defined(_WIN32) | ||||
|   std::wstring checked = L"[X] ";    /// Prefix for  a "checked" state. | ||||
| @@ -32,7 +35,7 @@ class CheckBox : public Component { | ||||
|   Decorator focused_style = inverted;   /// Decorator used when focused. | ||||
|   Decorator unfocused_style = nothing;  /// Decorator used when unfocused. | ||||
|  | ||||
|   /// Called when the user change the state of the CheckBox. | ||||
|   /// Called when the user change the state of the CheckboxBase. | ||||
|   std::function<void()> on_change = []() {}; | ||||
|  | ||||
|   // Component implementation. | ||||
| @@ -42,6 +45,8 @@ class CheckBox : public Component { | ||||
|  private: | ||||
|   bool OnMouseEvent(Event event); | ||||
|  | ||||
|   const std::wstring* const label_; | ||||
|   bool* const state_; | ||||
|   int cursor_position = 0; | ||||
|   Box box_; | ||||
| }; | ||||
|   | ||||
| @@ -1,77 +1,45 @@ | ||||
| #ifndef FTXUI_COMPONENT_COMPONENT_HPP | ||||
| #define FTXUI_COMPONENT_COMPONENT_HPP | ||||
| #ifndef FTXUI_COMPONENT_HPP | ||||
| #define FTXUI_COMPONENT_HPP | ||||
|  | ||||
| #include <memory>  // for unique_ptr | ||||
| #include <functional>  // for function | ||||
| #include <memory>      // for shared_ptr, make_shared | ||||
| #include <string>      // for wstring | ||||
| #include <vector>      // for vector | ||||
|  | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for CaptureMouse | ||||
| #include "ftxui/dom/elements.hpp"             // for Element | ||||
| #include "ftxui/component/component_base.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| class Delegate; | ||||
| class Focus; | ||||
| struct Event; | ||||
| class ComponentBase; | ||||
|  | ||||
| /// @brief It implement rendering itself as ftxui::Element. It implement | ||||
| /// keyboard navigation by responding to ftxui::Event. | ||||
| /// @ingroup component | ||||
| class Component { | ||||
|  public: | ||||
|   // Constructor/Destructor. | ||||
|   Component() = default; | ||||
|   virtual ~Component(); | ||||
| using Component = std::shared_ptr<ComponentBase>; | ||||
| using Components = std::vector<Component>; | ||||
|  | ||||
|   // Component hierarchy. | ||||
|   Component* Parent(); | ||||
|   void Add(Component* children); | ||||
| template <class T, class... Args> | ||||
| std::shared_ptr<T> Make(Args&&... args) { | ||||
|   return std::make_shared<T>(args...); | ||||
| } | ||||
|  | ||||
|   // Renders the component. | ||||
|   virtual Element Render(); | ||||
| Component Button(const std::wstring* label, std::function<void()> on_click); | ||||
| Component Checkbox(const std::wstring* label, bool* checked); | ||||
| 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); | ||||
|  | ||||
|   // Handles an event. | ||||
|   // By default, reduce on children with a lazy OR. | ||||
|   // | ||||
|   // Returns whether the event was handled or not. | ||||
|   virtual bool OnEvent(Event); | ||||
| template <class T>  // T = {int, float} | ||||
| Component Slider(std::wstring label, T* value, T min, T max, T increment); | ||||
|  | ||||
|   // 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* ActiveChild(); | ||||
| // namespace Component { | ||||
| // Component Vertical(Components children); | ||||
| // Component Horizontal(Components children); | ||||
| // Component Tab(int* selector, Components children); | ||||
| //}  // namespace Component | ||||
|  | ||||
|   // Whether this is the active child of its parent. | ||||
|   bool Active(); | ||||
|   // Whether all the ancestors are active. | ||||
|   bool Focused(); | ||||
| };  // namespace ftxui | ||||
|  | ||||
|   // Make the |child| to be the "active" one. | ||||
|   virtual void SetActiveChild(Component* child); | ||||
| #endif /* end of include guard: FTXUI_COMPONENT_HPP */ | ||||
|  | ||||
|   // Configure all the ancestors to give focus to this component. | ||||
|   void TakeFocus(); | ||||
|  | ||||
|  protected: | ||||
|   CapturedMouse CaptureMouse(const Event& event); | ||||
|  | ||||
|   std::vector<Component*> children_; | ||||
|  | ||||
|  private: | ||||
|   Component* parent_ = nullptr; | ||||
|   void Detach(); | ||||
|   void Attach(Component* parent); | ||||
| }; | ||||
|  | ||||
| using ComponentPtr = std::unique_ptr<Component>; | ||||
|  | ||||
| }  // namespace ftxui | ||||
|  | ||||
| #endif /* end of include guard: FTXUI_COMPONENT_COMPONENT_HPP */ | ||||
|  | ||||
| // Copyright 2020 Arthur Sonzogni. All rights reserved. | ||||
| // 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. | ||||
|   | ||||
							
								
								
									
										81
									
								
								include/ftxui/component/component_base.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								include/ftxui/component/component_base.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | ||||
| #ifndef FTXUI_COMPONENT_BASE_HPP | ||||
| #define FTXUI_COMPONENT_BASE_HPP | ||||
|  | ||||
| #include <memory>  // for unique_ptr | ||||
| #include <vector>  // for vector | ||||
|  | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for CaptureMouse | ||||
| #include "ftxui/dom/elements.hpp"              // for Element | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| class Delegate; | ||||
| class Focus; | ||||
| struct Event; | ||||
|  | ||||
| class ComponentBase; | ||||
| using Component = std::shared_ptr<ComponentBase>; | ||||
| using Components = std::vector<Component>; | ||||
|  | ||||
| /// @brief It implement rendering itself as ftxui::Element. It implement | ||||
| /// keyboard navigation by responding to ftxui::Event. | ||||
| /// @ingroup component | ||||
| class ComponentBase { | ||||
|  public: | ||||
|   // Constructor/Destructor. | ||||
|   ComponentBase() = default; | ||||
|   virtual ~ComponentBase(); | ||||
|  | ||||
|   // ComponentBase hierarchy. | ||||
|   ComponentBase* Parent(); | ||||
|   void Add(Component children); | ||||
|  | ||||
|   // Renders the component. | ||||
|   virtual Element Render(); | ||||
|  | ||||
|   // Handles an event. | ||||
|   // By default, reduce on children with a lazy OR. | ||||
|   // | ||||
|   // Returns whether the event was handled or not. | ||||
|   virtual bool OnEvent(Event); | ||||
|  | ||||
|   // 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 ActiveChild(); | ||||
|  | ||||
|   // Whether this is the active child of its parent. | ||||
|   bool Active(); | ||||
|   // Whether all the ancestors are active. | ||||
|   bool Focused(); | ||||
|  | ||||
|   // Make the |child| to be the "active" one. | ||||
|   virtual void SetActiveChild(ComponentBase* child); | ||||
|   void SetActiveChild(Component child); | ||||
|  | ||||
|   // Configure all the ancestors to give focus to this component. | ||||
|   void TakeFocus(); | ||||
|  | ||||
|  protected: | ||||
|   CapturedMouse CaptureMouse(const Event& event); | ||||
|  | ||||
|   std::vector<Component> children_; | ||||
|  | ||||
|  private: | ||||
|   ComponentBase* parent_ = nullptr; | ||||
|   void Detach(); | ||||
| }; | ||||
|  | ||||
| using Component = std::shared_ptr<ComponentBase>; | ||||
|  | ||||
| }  // namespace ftxui | ||||
|  | ||||
| #endif /* end of include guard: FTXUI_COMPONENT_BASE_HPP */ | ||||
|  | ||||
| // Copyright 2020 Arthur Sonzogni. All rights reserved. | ||||
| // Use of this source code is governed by the MIT license that can be found in | ||||
| // the LICENSE file. | ||||
| @@ -1,26 +1,32 @@ | ||||
| #ifndef FTXUI_COMPONENT_CONTAINER_HPP | ||||
| #define FTXUI_COMPONENT_CONTAINER_HPP | ||||
|  | ||||
| #include "ftxui/component/component.hpp" | ||||
| #include "ftxui/component/event.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/component/component.hpp"       // for Component, Components | ||||
| #include "ftxui/component/component_base.hpp"  // for ComponentBase | ||||
| #include "ftxui/component/event.hpp"           // for Event | ||||
| #include "ftxui/dom/elements.hpp"              // for Element | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| /// @brief A component where focus and events are automatically handled for you. | ||||
| class Container : public Component { | ||||
| class Container : public ComponentBase { | ||||
|  public: | ||||
|   static Container Vertical(); | ||||
|   static Container Horizontal(); | ||||
|   static Container Tab(int* selector); | ||||
|   static Component Vertical(); | ||||
|   static Component Vertical(Components children); | ||||
|  | ||||
|   static Component Horizontal(); | ||||
|   static Component Horizontal(Components children); | ||||
|  | ||||
|   static Component Tab(int* selector); | ||||
|   static Component Tab(int* selector, Components children); | ||||
|  | ||||
|   ~Container() override = default; | ||||
|  | ||||
|   // Component override. | ||||
|   bool OnEvent(Event event) override; | ||||
|   Element Render() override; | ||||
|   Component* ActiveChild() override; | ||||
|   virtual void SetActiveChild(Component*) override; | ||||
|   Component ActiveChild() override; | ||||
|   virtual void SetActiveChild(ComponentBase*) override; | ||||
|  | ||||
|  protected: | ||||
|   // Handlers | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
| namespace ftxui { | ||||
|  | ||||
| class ScreenInteractive; | ||||
| class Component; | ||||
| class ComponentBase; | ||||
|  | ||||
| /// @brief Represent an event. It can be key press event, a terminal resize, or | ||||
| /// more ... | ||||
| @@ -76,7 +76,7 @@ struct Event { | ||||
|  | ||||
|   //--- State section ---------------------------------------------------------- | ||||
|  private: | ||||
|   friend Component; | ||||
|   friend ComponentBase; | ||||
|   friend ScreenInteractive; | ||||
|   enum class Type { | ||||
|     Unknown, | ||||
|   | ||||
| @@ -1,27 +1,29 @@ | ||||
| #ifndef FTXUI_COMPONENT_INPUT_H_ | ||||
| #define FTXUI_COMPONENT_INPUT_H_ | ||||
|  | ||||
| #include <functional> | ||||
| #include <string> | ||||
| #include <functional>  // for function | ||||
| #include <string>      // for wstring | ||||
|  | ||||
| #include "ftxui/component/component.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/screen/box.hpp" | ||||
| #include "ftxui/component/component.hpp"       // for Component | ||||
| #include "ftxui/component/component_base.hpp"  // for ComponentBase | ||||
| #include "ftxui/dom/elements.hpp"              // for Element | ||||
| #include "ftxui/screen/box.hpp"                // for Box | ||||
|  | ||||
| namespace ftxui { | ||||
| struct Event; | ||||
|  | ||||
| /// @brief An input box. The user can type text into it. | ||||
| /// @ingroup component. | ||||
| class Input : public Component { | ||||
| class InputBase : public ComponentBase { | ||||
|  public: | ||||
|   // Access this interface from a Component | ||||
|   static InputBase* From(Component component); | ||||
|  | ||||
|   // Constructor. | ||||
|   Input() = default; | ||||
|   ~Input() override = default; | ||||
|   InputBase(std::wstring* content, const std::wstring* placeholder); | ||||
|   ~InputBase() override = default; | ||||
|  | ||||
|   // State. | ||||
|   std::wstring content; | ||||
|   std::wstring placeholder; | ||||
|   int cursor_position = 0; | ||||
|  | ||||
|   // State update callback. | ||||
| @@ -33,6 +35,9 @@ class Input : public Component { | ||||
|   bool OnEvent(Event) override; | ||||
|  | ||||
|  private: | ||||
|   std::wstring* const content_; | ||||
|   const std::wstring* const placeholder_; | ||||
|  | ||||
|   bool OnMouseEvent(Event); | ||||
|   Box input_box_; | ||||
|   Box cursor_box_; | ||||
|   | ||||
| @@ -1,28 +1,30 @@ | ||||
| #ifndef FTXUI_COMPONENT_MENU | ||||
| #define FTXUI_COMPONENT_MENU | ||||
|  | ||||
| #include <functional> | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include <functional>  // for function | ||||
| #include <string>      // for wstring | ||||
| #include <vector>      // for vector | ||||
|  | ||||
| #include "ftxui/component/component.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/screen/box.hpp" | ||||
| #include "ftxui/component/component.hpp"       // for Component | ||||
| #include "ftxui/component/component_base.hpp"  // for ComponentBase | ||||
| #include "ftxui/dom/elements.hpp"  // for Element, Decorator, operator|, bold, inverted, nothing | ||||
| #include "ftxui/screen/box.hpp"  // for Box | ||||
|  | ||||
| namespace ftxui { | ||||
| struct Event; | ||||
|  | ||||
| /// @brief A list of items. The user can navigate through them. | ||||
| /// @ingroup component | ||||
| class Menu : public Component { | ||||
| class MenuBase : public ComponentBase { | ||||
|  public: | ||||
|   // Access this interface from a Component | ||||
|   static MenuBase* From(Component component); | ||||
|  | ||||
|   // Constructor. | ||||
|   Menu() = default; | ||||
|   ~Menu() override = default; | ||||
|   MenuBase(const std::vector<std::wstring>* entries, int* selected_); | ||||
|   ~MenuBase() override = default; | ||||
|  | ||||
|   // State. | ||||
|   std::vector<std::wstring> entries = {}; | ||||
|   int selected = 0; | ||||
|   int focused = 0; | ||||
|  | ||||
|   Decorator normal_style = nothing; | ||||
| @@ -38,7 +40,10 @@ class Menu : public Component { | ||||
|   Element Render() override; | ||||
|   bool OnEvent(Event) override; | ||||
|  | ||||
|  private: | ||||
|  protected: | ||||
|   const std::vector<std::wstring>* const entries_; | ||||
|   int* selected_ = 0; | ||||
|  | ||||
|   bool OnMouseEvent(Event); | ||||
|  | ||||
|   std::vector<Box> boxes_; | ||||
|   | ||||
| @@ -1,12 +1,14 @@ | ||||
| #ifndef FTXUI_COMPONENT_RADIOBOX_HPP | ||||
| #define FTXUI_COMPONENT_RADIOBOX_HPP | ||||
|  | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include <functional>  // for function | ||||
| #include <string>      // for wstring, allocator | ||||
| #include <vector>      // for vector | ||||
|  | ||||
| #include "ftxui/component/component.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/screen/box.hpp" | ||||
| #include "ftxui/component/component.hpp"       // for Component | ||||
| #include "ftxui/component/component_base.hpp"  // for ComponentBase | ||||
| #include "ftxui/dom/elements.hpp"  // for Element, Decorator, inverted, nothing | ||||
| #include "ftxui/screen/box.hpp"    // for Box | ||||
|  | ||||
| namespace ftxui { | ||||
| struct Event; | ||||
| @@ -14,15 +16,16 @@ struct Event; | ||||
| /// @brief A list of selectable element. One and only one can be selected at | ||||
| /// the same time. | ||||
| /// @ingroup component | ||||
| class RadioBox : public Component { | ||||
| class RadioboxBase : public ComponentBase { | ||||
|  public: | ||||
|   // Constructor. | ||||
|   RadioBox() = default; | ||||
|   ~RadioBox() override = default; | ||||
|   // Access this interface from a Component | ||||
|   static RadioboxBase* From(Component component); | ||||
|  | ||||
|   // Constructor. | ||||
|   RadioboxBase(const std::vector<std::wstring>* entries, int* selected); | ||||
|   ~RadioboxBase() override = default; | ||||
|  | ||||
|   int selected = 0; | ||||
|   int focused = 0; | ||||
|   std::vector<std::wstring> entries; | ||||
|  | ||||
| #if defined(_WIN32) | ||||
|   std::wstring checked = L"(*) "; | ||||
| @@ -43,6 +46,9 @@ class RadioBox : public Component { | ||||
|   bool OnEvent(Event) override; | ||||
|  | ||||
|  private: | ||||
|   const std::vector<std::wstring>* const entries_; | ||||
|   int* const selected_; | ||||
|  | ||||
|   bool OnMouseEvent(Event event); | ||||
|   int cursor_position = 0; | ||||
|   std::vector<Box> boxes_; | ||||
|   | ||||
| @@ -3,7 +3,8 @@ | ||||
|  | ||||
| #include <atomic>  // for atomic | ||||
| #include <ftxui/component/receiver.hpp> | ||||
| #include <memory>  // for unique_ptr | ||||
| #include <functional>  // for function | ||||
| #include <memory>      // for unique_ptr, shared_ptr | ||||
| #include <string>      // for string | ||||
|  | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for CapturedMouse | ||||
| @@ -11,7 +12,9 @@ | ||||
| #include "ftxui/screen/screen.hpp"  // for Screen | ||||
|  | ||||
| namespace ftxui { | ||||
| class Component; | ||||
| class ComponentBase; | ||||
|  | ||||
| using Component = std::shared_ptr<ComponentBase>; | ||||
| struct Event; | ||||
|  | ||||
| class ScreenInteractive : public Screen { | ||||
| @@ -22,15 +25,15 @@ class ScreenInteractive : public Screen { | ||||
|   static ScreenInteractive TerminalOutput(); | ||||
|  | ||||
|   ~ScreenInteractive(); | ||||
|   void Loop(Component*); | ||||
|   void Loop(Component); | ||||
|   std::function<void()> ExitLoopClosure(); | ||||
|  | ||||
|   void PostEvent(Event event); | ||||
|   CapturedMouse CaptureMouse(); | ||||
|  | ||||
|  private: | ||||
|   void Draw(Component* component); | ||||
|   void EventLoop(Component* component); | ||||
|   void Draw(Component component); | ||||
|   void EventLoop(Component component); | ||||
|  | ||||
|   enum class Dimension { | ||||
|     FitComponent, | ||||
|   | ||||
| @@ -1,23 +0,0 @@ | ||||
| #ifndef FTXUI_COMPONENT_SLIDER_HPP | ||||
| #define FTXUI_COMPONENT_SLIDER_HPP | ||||
|  | ||||
| #include <string> | ||||
| #include "ftxui/component/component.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
| // ComponentPtr Slider(std::string label, | ||||
| // float* value, | ||||
| // float min = 0.f, | ||||
| // float max = 100.f, | ||||
| // float increment = (max - min) * 0.05f); | ||||
|  | ||||
| template <class T>  // T = {int, float} | ||||
| ComponentPtr Slider(std::wstring label, T* value, T min, T max, T increment); | ||||
|  | ||||
| }  // namespace ftxui | ||||
|  | ||||
| #endif /* end of include guard: FTXUI_COMPONENT_SLIDER_HPP */ | ||||
|  | ||||
| // Copyright 2020 Arthur Sonzogni. All rights reserved. | ||||
| // Use of this source code is governed by the MIT license that can be found in | ||||
| // the LICENSE file. | ||||
| @@ -1,26 +1,30 @@ | ||||
| #ifndef FTXUI_COMPONENT_TOGGLE_H_ | ||||
| #define FTXUI_COMPONENT_TOGGLE_H_ | ||||
|  | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include <functional>  // for function | ||||
| #include <string>      // for wstring | ||||
| #include <vector>      // for vector | ||||
|  | ||||
| #include "ftxui/component/component.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/screen/box.hpp" | ||||
| #include "ftxui/component/component.hpp"       // for Component | ||||
| #include "ftxui/component/component_base.hpp"  // for ComponentBase | ||||
| #include "ftxui/dom/elements.hpp"  // for Element, Decorator, operator|, bold, dim, inverted | ||||
| #include "ftxui/screen/box.hpp"  // for Box | ||||
|  | ||||
| namespace ftxui { | ||||
| struct Event; | ||||
|  | ||||
| /// @brief An horizontal list of elements. The user can navigate through them. | ||||
| /// @ingroup component | ||||
| class Toggle : public Component { | ||||
| class ToggleBase : public ComponentBase { | ||||
|  public: | ||||
|   // Access this interface from a Component | ||||
|   static ToggleBase* From(Component component); | ||||
|  | ||||
|   // Constructor. | ||||
|   ~Toggle() override = default; | ||||
|   ToggleBase(const std::vector<std::wstring>* entries, int* selected); | ||||
|   ~ToggleBase() override = default; | ||||
|  | ||||
|   // State. | ||||
|   std::vector<std::wstring> entries = {L"On", L"Off"}; | ||||
|   int selected = 0; | ||||
|   int focused = 0; | ||||
|  | ||||
|   Decorator normal_style = dim; | ||||
| @@ -36,7 +40,10 @@ class Toggle : public Component { | ||||
|   Element Render() override; | ||||
|   bool OnEvent(Event) override; | ||||
|  | ||||
|  private: | ||||
|  protected: | ||||
|   const std::vector<std::wstring>* const entries_; | ||||
|   int* selected_ = 0; | ||||
|  | ||||
|   bool OnMouseEvent(Event event); | ||||
|   std::vector<Box> boxes_; | ||||
| }; | ||||
|   | ||||
							
								
								
									
										3
									
								
								iwyu.imp
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								iwyu.imp
									
									
									
									
									
								
							| @@ -5,4 +5,7 @@ | ||||
|   { symbol: [ "ICANON", private, "<termios.h>", public ] }, | ||||
|   { symbol: [ "termios", private, "<termios.h>", public ] }, | ||||
|   { symbol: [ "TCSANOW", private, "<termios.h>", public ] }, | ||||
|   { symbol: [ "__shared_ptr_access", private, "", public ] }, | ||||
|   { symbol: [ "ftxui", private , "", public ] }, | ||||
|   { include: ["ext/alloc_traits.h", "private", "<memory>", "public"] } | ||||
| ] | ||||
|   | ||||
| @@ -9,12 +9,47 @@ | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| Element Button::Render() { | ||||
|   auto style = Focused() ? inverted : nothing; | ||||
|   return text(label) | border | style | reflect(box_); | ||||
| /// @brief Draw a button. Execute a function when clicked. | ||||
| /// @param label The label of the button. | ||||
| /// @param on_click The action to execute when clicked. | ||||
| /// @ingroup component | ||||
| /// @see ButtonBase | ||||
| /// | ||||
| /// ### Example | ||||
| /// | ||||
| /// ```cpp | ||||
| /// auto screen = ScreenInteractive::FitComponent(); | ||||
| /// std::wstring label = L"Click to quit"; | ||||
| /// Component button = Button(&label, screen.ExitLoopClosure()); | ||||
| /// screen.Loop(button) | ||||
| /// ``` | ||||
| /// | ||||
| /// ### Output | ||||
| /// | ||||
| /// ```bash | ||||
| /// ┌─────────────┐ | ||||
| /// │Click to quit│ | ||||
| /// └─────────────┘ | ||||
| /// ``` | ||||
| Component Button(const std::wstring* label, std::function<void()> on_click) { | ||||
|   return Make<ButtonBase>(label, on_click); | ||||
| } | ||||
|  | ||||
| bool Button::OnEvent(Event event) { | ||||
| // static | ||||
| ButtonBase* ButtonBase::From(Component component) { | ||||
|   return static_cast<ButtonBase*>(component.get()); | ||||
| } | ||||
|  | ||||
| ButtonBase::ButtonBase(const std::wstring* label, | ||||
|                        std::function<void()> on_click) | ||||
|     : label_(label), on_click_(on_click) {} | ||||
|  | ||||
| Element ButtonBase::Render() { | ||||
|   auto style = Focused() ? inverted : nothing; | ||||
|   return text(*label_) | border | style | reflect(box_); | ||||
| } | ||||
|  | ||||
| bool ButtonBase::OnEvent(Event event) { | ||||
|   if (event.is_mouse() && box_.Contain(event.mouse().x, event.mouse().y)) { | ||||
|     if (!CaptureMouse(event)) | ||||
|       return false; | ||||
| @@ -23,7 +58,7 @@ bool Button::OnEvent(Event event) { | ||||
|  | ||||
|     if (event.mouse().button == Mouse::Left && | ||||
|         event.mouse().motion == Mouse::Pressed) { | ||||
|       on_click(); | ||||
|       on_click_(); | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
| @@ -31,7 +66,7 @@ bool Button::OnEvent(Event event) { | ||||
|   } | ||||
|  | ||||
|   if (event == Event::Return) { | ||||
|     on_click(); | ||||
|     on_click_(); | ||||
|     return true; | ||||
|   } | ||||
|   return false; | ||||
|   | ||||
| @@ -9,28 +9,61 @@ | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| Element CheckBox::Render() { | ||||
| /// @brief Draw checkable element. | ||||
| /// @param label The label of the checkbox. | ||||
| /// @param checked Whether the checkbox is checked or not. | ||||
| /// @ingroup component | ||||
| /// @see CheckboxBase | ||||
| /// | ||||
| /// ### Example | ||||
| /// | ||||
| /// ```cpp | ||||
| /// auto screen = ScreenInteractive::FitComponent(); | ||||
| /// std::wstring label = L"Make a sandwidth"; | ||||
| /// bool checked = false; | ||||
| /// Component checkbox = Checkbox(&label, &checked); | ||||
| /// screen.Loop(checkbox) | ||||
| /// ``` | ||||
| /// | ||||
| /// ### Output | ||||
| /// | ||||
| /// ```bash | ||||
| /// ☐ Make a sandwitch | ||||
| /// ``` | ||||
| Component Checkbox(const std::wstring* label, bool* checked) { | ||||
|   return Make<CheckboxBase>(label, checked); | ||||
| } | ||||
|  | ||||
| // static | ||||
| CheckboxBase* From(Component component) { | ||||
|   return static_cast<CheckboxBase*>(component.get()); | ||||
| } | ||||
|  | ||||
| CheckboxBase::CheckboxBase(const std::wstring* label, bool* state) | ||||
|     : label_(label), state_(state) {} | ||||
|  | ||||
| Element CheckboxBase::Render() { | ||||
|   bool is_focused = Focused(); | ||||
|   auto style = is_focused ? focused_style : unfocused_style; | ||||
|   auto focus_management = is_focused ? focus : state ? select : nothing; | ||||
|   return hbox(text(state ? checked : unchecked), | ||||
|               text(label) | style | focus_management) | | ||||
|   auto focus_management = is_focused ? focus : *state_ ? select : nothing; | ||||
|   return hbox(text(*state_ ? checked : unchecked), | ||||
|               text(*label_) | style | focus_management) | | ||||
|          reflect(box_); | ||||
| } | ||||
|  | ||||
| bool CheckBox::OnEvent(Event event) { | ||||
| bool CheckboxBase::OnEvent(Event event) { | ||||
|   if (event.is_mouse()) | ||||
|     return OnMouseEvent(event); | ||||
|  | ||||
|   if (event == Event::Character(' ') || event == Event::Return) { | ||||
|     state = !state; | ||||
|     *state_ = !*state_; | ||||
|     on_change(); | ||||
|     return true; | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| bool CheckBox::OnMouseEvent(Event event) { | ||||
| bool CheckboxBase::OnMouseEvent(Event event) { | ||||
|   if (!CaptureMouse(event)) | ||||
|     return false; | ||||
|   if (!box_.Contain(event.mouse().x, event.mouse().y)) | ||||
| @@ -40,7 +73,7 @@ bool CheckBox::OnMouseEvent(Event event) { | ||||
|  | ||||
|   if (event.mouse().button == Mouse::Left && | ||||
|       event.mouse().motion == Mouse::Pressed) { | ||||
|     state = !state; | ||||
|     *state_ = !*state_; | ||||
|     on_change(); | ||||
|     return true; | ||||
|   } | ||||
|   | ||||
| @@ -1,10 +1,14 @@ | ||||
| #include <algorithm>           // for find_if | ||||
| #include <ext/alloc_traits.h>  // for __alloc_traits<>::value_type | ||||
| #include <iterator>            // for begin, end | ||||
| #include <utility>             // for move | ||||
|  | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for CapturedMouse, CapturedMouseInterface | ||||
| #include "ftxui/component/component.hpp" | ||||
|  | ||||
| #include <algorithm> | ||||
|  | ||||
| #include "ftxui/component/captured_mouse.hpp" | ||||
| #include "ftxui/component/event.hpp" | ||||
| #include "ftxui/component/screen_interactive.hpp" | ||||
| #include "ftxui/component/component_base.hpp"  // for ComponentBase, Component | ||||
| #include "ftxui/component/event.hpp"           // for Event | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for Component, ScreenInteractive | ||||
| #include "ftxui/dom/elements.hpp"                  // for text, Element | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| @@ -13,33 +17,35 @@ class CaptureMouseImpl : public CapturedMouseInterface { | ||||
|  public: | ||||
|   ~CaptureMouseImpl() override {} | ||||
| }; | ||||
| } | ||||
| }  // namespace | ||||
|  | ||||
| Component::~Component() { | ||||
| ComponentBase::~ComponentBase() { | ||||
|   Detach(); | ||||
| } | ||||
|  | ||||
| /// @brief Return the parent Component, or nul if any. | ||||
| /// @brief Return the parent ComponentBase, or nul if any. | ||||
| /// @see Attach | ||||
| /// @see Detach | ||||
| /// @see Parent | ||||
| /// @ingroup component | ||||
| Component* Component::Parent() { | ||||
| ComponentBase* ComponentBase::Parent() { | ||||
|   return parent_; | ||||
| } | ||||
|  | ||||
| /// @brief Add a children. | ||||
| /// @@param child The child to be attached. | ||||
| /// @ingroup component | ||||
| void Component::Add(Component* child) { | ||||
|   child->Attach(this); | ||||
| void ComponentBase::Add(Component child) { | ||||
|   child->Detach(); | ||||
|   child->parent_ = this; | ||||
|   children_.push_back(std::move(child)); | ||||
| } | ||||
|  | ||||
| /// @brief Draw the component. | ||||
| /// Build a ftxui::Element to be drawn on the ftxi::Screen representing this | ||||
| /// ftxui::Component. | ||||
| /// ftxui::ComponentBase. | ||||
| /// @ingroup component | ||||
| Element Component::Render() { | ||||
| Element ComponentBase::Render() { | ||||
|   if (children_.size() == 1) | ||||
|     return children_.front()->Render(); | ||||
|  | ||||
| @@ -52,8 +58,8 @@ Element Component::Render() { | ||||
| /// The default implementation called OnEvent on every child until one return | ||||
| /// true. If none returns true, return false. | ||||
| /// @ingroup component | ||||
| bool Component::OnEvent(Event event) { | ||||
|   for (Component* child : children_) { | ||||
| bool ComponentBase::OnEvent(Event event) { | ||||
|   for (Component& child : children_) { | ||||
|     if (child->OnEvent(event)) | ||||
|       return true; | ||||
|   } | ||||
| @@ -63,27 +69,27 @@ bool Component::OnEvent(Event event) { | ||||
| /// @brief Return the currently Active child. | ||||
| /// @return the currently Active child. | ||||
| /// @ingroup component | ||||
| Component* Component::ActiveChild() { | ||||
| Component ComponentBase::ActiveChild() { | ||||
|   return children_.empty() ? nullptr : children_.front(); | ||||
| } | ||||
|  | ||||
| /// @brief Returns if the element if the currently active child of its parent. | ||||
| /// @ingroup component | ||||
| bool Component::Active() { | ||||
|   return !parent_ || parent_->ActiveChild() == this; | ||||
| bool ComponentBase::Active() { | ||||
|   return !parent_ || parent_->ActiveChild().get() == this; | ||||
| } | ||||
|  | ||||
| /// @brief Returns if the elements if focused by the user. | ||||
| /// True when the Component is focused by the user. An element is Focused when | ||||
| /// it is with all its ancestors the ActiveChild() of their parents. | ||||
| /// True when the ComponentBase is focused by the user. An element is Focused | ||||
| /// when it is with all its ancestors the ActiveChild() of their parents. | ||||
| /// @ingroup component | ||||
| bool Component::Focused() { | ||||
|   Component* current = this; | ||||
| bool ComponentBase::Focused() { | ||||
|   ComponentBase* current = this; | ||||
|   for (;;) { | ||||
|     Component* parent = current->parent_; | ||||
|     ComponentBase* parent = current->parent_; | ||||
|     if (!parent) | ||||
|       return true; | ||||
|     if (parent->ActiveChild() != current) | ||||
|     if (parent->ActiveChild().get() != current) | ||||
|       return false; | ||||
|     current = parent; | ||||
|   } | ||||
| @@ -92,13 +98,20 @@ bool Component::Focused() { | ||||
| /// @brief Make the |child| to be the "active" one. | ||||
| /// @argument child the child to become active. | ||||
| /// @ingroup component | ||||
| void Component::SetActiveChild(Component*) {} | ||||
| void ComponentBase::SetActiveChild(ComponentBase*) {} | ||||
|  | ||||
| /// @brief Make the |child| to be the "active" one. | ||||
| /// @argument child the child to become active. | ||||
| /// @ingroup component | ||||
| void ComponentBase::SetActiveChild(Component child) { | ||||
|   SetActiveChild(child.get()); | ||||
| } | ||||
|  | ||||
| /// @brief Configure all the ancestors to give focus to this component. | ||||
| /// @ingroup component | ||||
| void Component::TakeFocus() { | ||||
|   Component* child = this; | ||||
|   Component* parent = parent_; | ||||
| void ComponentBase::TakeFocus() { | ||||
|   ComponentBase* child = this; | ||||
|   ComponentBase* parent = parent_; | ||||
|   while (parent) { | ||||
|     parent->SetActiveChild(child); | ||||
|     child = parent; | ||||
| @@ -110,7 +123,7 @@ void Component::TakeFocus() { | ||||
| /// them. It represents a component taking priority over others. | ||||
| /// @argument event | ||||
| /// @ingroup component | ||||
| CapturedMouse Component::CaptureMouse(const Event& event) { | ||||
| CapturedMouse ComponentBase::CaptureMouse(const Event& event) { | ||||
|   if (!event.screen_) | ||||
|     return std::make_unique<CaptureMouseImpl>(); | ||||
|   return event.screen_->CaptureMouse(); | ||||
| @@ -121,25 +134,17 @@ CapturedMouse Component::CaptureMouse(const Event& event) { | ||||
| /// @see Detach | ||||
| /// @see Parent | ||||
| /// @ingroup component | ||||
| void Component::Detach() { | ||||
| void ComponentBase::Detach() { | ||||
|   if (!parent_) | ||||
|     return; | ||||
|   auto it = std::find(std::begin(parent_->children_), | ||||
|                       std::end(parent_->children_), this); | ||||
|   auto it = std::find_if(std::begin(parent_->children_),  // | ||||
|                          std::end(parent_->children_),    // | ||||
|                          [this](const Component& that) {  // | ||||
|                            return this == that.get(); | ||||
|                          }); | ||||
|   parent_->children_.erase(it); | ||||
| } | ||||
|  | ||||
| /// @brief Attach this element to its parent. | ||||
| /// @see Attach | ||||
| /// @see Detach | ||||
| /// @see Parent | ||||
| /// @ingroup component | ||||
| void Component::Attach(Component* parent) { | ||||
|   Detach(); | ||||
|   parent_ = parent; | ||||
|   parent_->children_.push_back(this); | ||||
| } | ||||
|  | ||||
| }  // namespace ftxui | ||||
|  | ||||
| // Copyright 2020 Arthur Sonzogni. All rights reserved. | ||||
|   | ||||
| @@ -1,33 +1,69 @@ | ||||
| #include "ftxui/component/container.hpp" | ||||
| #include <stddef.h>            // for size_t | ||||
| #include <algorithm>           // for max, min | ||||
| #include <ext/alloc_traits.h>  // for __alloc_traits<>::value_type | ||||
| #include <memory>  // for __shared_ptr_access, shared_ptr, make_shared, __shared_ptr_access<>::element_type, allocator_traits<>::value_type | ||||
| #include <utility>  // for move | ||||
| #include <vector>   // for vector, allocator | ||||
|  | ||||
| #include <stddef.h> | ||||
| #include <algorithm> | ||||
| #include <vector> | ||||
| #include "ftxui/component/container.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| Component ContainerVertical(Components children) { | ||||
|   return Container::Vertical(std::move(children)); | ||||
| } | ||||
|  | ||||
| Component ContainerHorizontal(Components children) { | ||||
|   return Container::Horizontal(std::move(children)); | ||||
| } | ||||
|  | ||||
| Component ContainerTab(int* selector, Components children) { | ||||
|   return Container::Tab(selector, std::move(children)); | ||||
| } | ||||
|  | ||||
| // static | ||||
| Container Container::Horizontal() { | ||||
|   Container container; | ||||
|   container.event_handler_ = &Container::HorizontalEvent; | ||||
|   container.render_handler_ = &Container::HorizontalRender; | ||||
| Component Container::Vertical() { | ||||
|   return Vertical({}); | ||||
| } | ||||
|  | ||||
| // static | ||||
| Component Container::Vertical(Components children) { | ||||
|   auto container = std::make_shared<Container>(); | ||||
|   container->event_handler_ = &Container::VerticalEvent; | ||||
|   container->render_handler_ = &Container::VerticalRender; | ||||
|   for (Component& child : children) | ||||
|     container->Add(std::move(child)); | ||||
|   return container; | ||||
| } | ||||
|  | ||||
| // static | ||||
| Container Container::Vertical() { | ||||
|   Container container; | ||||
|   container.event_handler_ = &Container::VerticalEvent; | ||||
|   container.render_handler_ = &Container::VerticalRender; | ||||
| Component Container::Horizontal() { | ||||
|   return Horizontal({}); | ||||
| } | ||||
|  | ||||
| // static | ||||
| Component Container::Horizontal(Components children) { | ||||
|   auto container = std::make_shared<Container>(); | ||||
|   container->event_handler_ = &Container::HorizontalEvent; | ||||
|   container->render_handler_ = &Container::HorizontalRender; | ||||
|   for (Component& child : children) | ||||
|     container->Add(std::move(child)); | ||||
|   return container; | ||||
| } | ||||
|  | ||||
| // static | ||||
| Container Container::Tab(int* selector) { | ||||
|   Container container; | ||||
|   container.event_handler_ = &Container::TabEvent; | ||||
|   container.render_handler_ = &Container::TabRender; | ||||
|   container.selector_ = selector; | ||||
| Component Container::Tab(int* selector) { | ||||
|   return Tab(selector, {}); | ||||
| } | ||||
|  | ||||
| // static | ||||
| Component Container::Tab(int* selector, Components children) { | ||||
|   auto container = std::make_shared<Container>(); | ||||
|   container->selector_ = selector; | ||||
|   container->event_handler_ = &Container::TabEvent; | ||||
|   container->render_handler_ = &Container::TabRender; | ||||
|   for (Component& child : children) | ||||
|     container->Add(std::move(child)); | ||||
|   return container; | ||||
| } | ||||
|  | ||||
| @@ -44,7 +80,7 @@ bool Container::OnEvent(Event event) { | ||||
|   return (this->*event_handler_)(event); | ||||
| } | ||||
|  | ||||
| Component* Container::ActiveChild() { | ||||
| Component Container::ActiveChild() { | ||||
|   if (children_.size() == 0) | ||||
|     return nullptr; | ||||
|  | ||||
| @@ -52,9 +88,9 @@ Component* Container::ActiveChild() { | ||||
|   return children_[selected % children_.size()]; | ||||
| } | ||||
|  | ||||
| void Container::SetActiveChild(Component* child) { | ||||
| void Container::SetActiveChild(ComponentBase* child) { | ||||
|   for (size_t i = 0; i < children_.size(); ++i) { | ||||
|     if (children_[i] == child) { | ||||
|     if (children_[i].get() == child) { | ||||
|       (selector_ ? *selector_ : selected_) = i; | ||||
|       return; | ||||
|     } | ||||
| @@ -114,7 +150,7 @@ Element Container::HorizontalRender() { | ||||
| } | ||||
|  | ||||
| Element Container::TabRender() { | ||||
|   Component* active_child = ActiveChild(); | ||||
|   Component active_child = ActiveChild(); | ||||
|   if (active_child) | ||||
|     return active_child->Render(); | ||||
|   return text(L"Empty container"); | ||||
| @@ -124,7 +160,7 @@ bool Container::OnMouseEvent(Event event) { | ||||
|   if (selector_) | ||||
|     return ActiveChild()->OnEvent(event); | ||||
|  | ||||
|   for (Component* child : children_) { | ||||
|   for (Component& child : children_) { | ||||
|     if (child->OnEvent(event)) | ||||
|       return true; | ||||
|   } | ||||
|   | ||||
| @@ -1,205 +1,205 @@ | ||||
| #include <gtest/gtest-message.h>  // for Message | ||||
| #include <gtest/gtest-test-part.h>  // for TestPartResult, SuiteApiResolver | ||||
| #include <memory>                   // for allocator | ||||
| #include <gtest/gtest-test-part.h>  // for TestPartResult, SuiteApiResolver, TestFactoryImpl | ||||
| #include <memory>  // for __shared_ptr_access, shared_ptr, allocator | ||||
|  | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for ftxui | ||||
| #include "ftxui/component/container.hpp" | ||||
| #include "ftxui/screen/box.hpp"     // for ftxui | ||||
| #include "gtest/gtest_pred_impl.h"  // for AssertionResult, EXPECT_EQ, EXPEC... | ||||
| #include "gtest/gtest_pred_impl.h"  // for AssertionResult, EXPECT_EQ, EXPECT_FALSE, EXPECT_TRUE, Test, TEST | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| TEST(ContainerTest, HorizontalEvent) { | ||||
|   auto container = Container::Horizontal(); | ||||
|   Component c0, c1, c2; | ||||
|   container.Add(&c0); | ||||
|   container.Add(&c1); | ||||
|   container.Add(&c2); | ||||
|   container->Add(c0); | ||||
|   container->Add(c1); | ||||
|   container->Add(c2); | ||||
|  | ||||
|   // With arrow key. | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container.OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c1); | ||||
|   container.OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c2); | ||||
|   container.OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c2); | ||||
|   container.OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c1); | ||||
|   container.OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container.OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|   container->OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(container->ActiveChild(), c1); | ||||
|   container->OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(container->ActiveChild(), c2); | ||||
|   container->OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(container->ActiveChild(), c2); | ||||
|   container->OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(container->ActiveChild(), c1); | ||||
|   container->OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|   container->OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|  | ||||
|   // With arrow key in the wrong dimension. | ||||
|   container.OnEvent(Event::ArrowUp); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container.OnEvent(Event::ArrowDown); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container->OnEvent(Event::ArrowUp); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|   container->OnEvent(Event::ArrowDown); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|  | ||||
|   // With vim like characters. | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container.OnEvent(Event::Character('l')); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c1); | ||||
|   container.OnEvent(Event::Character('l')); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c2); | ||||
|   container.OnEvent(Event::Character('l')); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c2); | ||||
|   container.OnEvent(Event::Character('h')); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c1); | ||||
|   container.OnEvent(Event::Character('h')); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container.OnEvent(Event::Character('h')); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|   container->OnEvent(Event::Character('l')); | ||||
|   EXPECT_EQ(container->ActiveChild(), c1); | ||||
|   container->OnEvent(Event::Character('l')); | ||||
|   EXPECT_EQ(container->ActiveChild(), c2); | ||||
|   container->OnEvent(Event::Character('l')); | ||||
|   EXPECT_EQ(container->ActiveChild(), c2); | ||||
|   container->OnEvent(Event::Character('h')); | ||||
|   EXPECT_EQ(container->ActiveChild(), c1); | ||||
|   container->OnEvent(Event::Character('h')); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|   container->OnEvent(Event::Character('h')); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|  | ||||
|   // With vim like characters in the wrong direction. | ||||
|   container.OnEvent(Event::Character('j')); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container.OnEvent(Event::Character('k')); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container->OnEvent(Event::Character('j')); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|   container->OnEvent(Event::Character('k')); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|  | ||||
|   // With tab characters. | ||||
|   container.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c1); | ||||
|   container.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c2); | ||||
|   container.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c1); | ||||
|   container.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c2); | ||||
|   container.OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c1); | ||||
|   container.OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container.OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c2); | ||||
|   container.OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c1); | ||||
|   container.OnEvent(Event::TabReverse); | ||||
|   container->OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container->ActiveChild(), c1); | ||||
|   container->OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container->ActiveChild(), c2); | ||||
|   container->OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|   container->OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container->ActiveChild(), c1); | ||||
|   container->OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container->ActiveChild(), c2); | ||||
|   container->OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(container->ActiveChild(), c1); | ||||
|   container->OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|   container->OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(container->ActiveChild(), c2); | ||||
|   container->OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(container->ActiveChild(), c1); | ||||
|   container->OnEvent(Event::TabReverse); | ||||
| } | ||||
|  | ||||
| TEST(ContainerTest, VerticalEvent) { | ||||
|   auto container = Container::Vertical(); | ||||
|   Component c0, c1, c2; | ||||
|   container.Add(&c0); | ||||
|   container.Add(&c1); | ||||
|   container.Add(&c2); | ||||
|   container->Add(c0); | ||||
|   container->Add(c1); | ||||
|   container->Add(c2); | ||||
|  | ||||
|   // With arrow key. | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container.OnEvent(Event::ArrowDown); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c1); | ||||
|   container.OnEvent(Event::ArrowDown); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c2); | ||||
|   container.OnEvent(Event::ArrowDown); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c2); | ||||
|   container.OnEvent(Event::ArrowUp); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c1); | ||||
|   container.OnEvent(Event::ArrowUp); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container.OnEvent(Event::ArrowUp); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|   container->OnEvent(Event::ArrowDown); | ||||
|   EXPECT_EQ(container->ActiveChild(), c1); | ||||
|   container->OnEvent(Event::ArrowDown); | ||||
|   EXPECT_EQ(container->ActiveChild(), c2); | ||||
|   container->OnEvent(Event::ArrowDown); | ||||
|   EXPECT_EQ(container->ActiveChild(), c2); | ||||
|   container->OnEvent(Event::ArrowUp); | ||||
|   EXPECT_EQ(container->ActiveChild(), c1); | ||||
|   container->OnEvent(Event::ArrowUp); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|   container->OnEvent(Event::ArrowUp); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|  | ||||
|   // With arrow key in the wrong dimension. | ||||
|   container.OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container.OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container->OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|   container->OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|  | ||||
|   // With vim like characters. | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container.OnEvent(Event::Character('j')); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c1); | ||||
|   container.OnEvent(Event::Character('j')); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c2); | ||||
|   container.OnEvent(Event::Character('j')); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c2); | ||||
|   container.OnEvent(Event::Character('k')); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c1); | ||||
|   container.OnEvent(Event::Character('k')); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container.OnEvent(Event::Character('k')); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|   container->OnEvent(Event::Character('j')); | ||||
|   EXPECT_EQ(container->ActiveChild(), c1); | ||||
|   container->OnEvent(Event::Character('j')); | ||||
|   EXPECT_EQ(container->ActiveChild(), c2); | ||||
|   container->OnEvent(Event::Character('j')); | ||||
|   EXPECT_EQ(container->ActiveChild(), c2); | ||||
|   container->OnEvent(Event::Character('k')); | ||||
|   EXPECT_EQ(container->ActiveChild(), c1); | ||||
|   container->OnEvent(Event::Character('k')); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|   container->OnEvent(Event::Character('k')); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|  | ||||
|   // With vim like characters in the wrong direction. | ||||
|   container.OnEvent(Event::Character('h')); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container.OnEvent(Event::Character('l')); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container->OnEvent(Event::Character('h')); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|   container->OnEvent(Event::Character('l')); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|  | ||||
|   // With tab characters. | ||||
|   container.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c1); | ||||
|   container.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c2); | ||||
|   container.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c1); | ||||
|   container.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c2); | ||||
|   container.OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c1); | ||||
|   container.OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   container.OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c2); | ||||
|   container.OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c1); | ||||
|   container.OnEvent(Event::TabReverse); | ||||
|   container->OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container->ActiveChild(), c1); | ||||
|   container->OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container->ActiveChild(), c2); | ||||
|   container->OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|   container->OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container->ActiveChild(), c1); | ||||
|   container->OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(container->ActiveChild(), c2); | ||||
|   container->OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(container->ActiveChild(), c1); | ||||
|   container->OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|   container->OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(container->ActiveChild(), c2); | ||||
|   container->OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(container->ActiveChild(), c1); | ||||
|   container->OnEvent(Event::TabReverse); | ||||
| } | ||||
|  | ||||
| TEST(ContainerTest, SetActiveChild) { | ||||
|   auto container = Container::Horizontal(); | ||||
|   Component c0, c1, c2; | ||||
|   container.Add(&c0); | ||||
|   container.Add(&c1); | ||||
|   container.Add(&c2); | ||||
|   container->Add(c0); | ||||
|   container->Add(c1); | ||||
|   container->Add(c2); | ||||
|  | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   EXPECT_TRUE(c0.Focused()); | ||||
|   EXPECT_TRUE(c0.Active()); | ||||
|   EXPECT_FALSE(c1.Focused()); | ||||
|   EXPECT_FALSE(c1.Active()); | ||||
|   EXPECT_FALSE(c2.Focused()); | ||||
|   EXPECT_FALSE(c2.Active()); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|   EXPECT_TRUE(c0->Focused()); | ||||
|   EXPECT_TRUE(c0->Active()); | ||||
|   EXPECT_FALSE(c1->Focused()); | ||||
|   EXPECT_FALSE(c1->Active()); | ||||
|   EXPECT_FALSE(c2->Focused()); | ||||
|   EXPECT_FALSE(c2->Active()); | ||||
|  | ||||
|   container.SetActiveChild(&c0); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   EXPECT_TRUE(c0.Focused()); | ||||
|   EXPECT_TRUE(c0.Active()); | ||||
|   EXPECT_FALSE(c1.Focused()); | ||||
|   EXPECT_FALSE(c1.Active()); | ||||
|   EXPECT_FALSE(c2.Focused()); | ||||
|   EXPECT_FALSE(c2.Active()); | ||||
|   container->SetActiveChild(c0); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|   EXPECT_TRUE(c0->Focused()); | ||||
|   EXPECT_TRUE(c0->Active()); | ||||
|   EXPECT_FALSE(c1->Focused()); | ||||
|   EXPECT_FALSE(c1->Active()); | ||||
|   EXPECT_FALSE(c2->Focused()); | ||||
|   EXPECT_FALSE(c2->Active()); | ||||
|  | ||||
|   container.SetActiveChild(&c1); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c1); | ||||
|   EXPECT_FALSE(c0.Focused()); | ||||
|   EXPECT_FALSE(c0.Active()); | ||||
|   EXPECT_TRUE(c1.Focused()); | ||||
|   EXPECT_TRUE(c1.Active()); | ||||
|   EXPECT_FALSE(c2.Focused()); | ||||
|   EXPECT_FALSE(c2.Active()); | ||||
|   container->SetActiveChild(c1); | ||||
|   EXPECT_EQ(container->ActiveChild(), c1); | ||||
|   EXPECT_FALSE(c0->Focused()); | ||||
|   EXPECT_FALSE(c0->Active()); | ||||
|   EXPECT_TRUE(c1->Focused()); | ||||
|   EXPECT_TRUE(c1->Active()); | ||||
|   EXPECT_FALSE(c2->Focused()); | ||||
|   EXPECT_FALSE(c2->Active()); | ||||
|  | ||||
|   container.SetActiveChild(&c2); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c2); | ||||
|   EXPECT_FALSE(c0.Focused()); | ||||
|   EXPECT_FALSE(c0.Active()); | ||||
|   EXPECT_FALSE(c1.Focused()); | ||||
|   EXPECT_FALSE(c1.Active()); | ||||
|   EXPECT_TRUE(c2.Focused()); | ||||
|   EXPECT_TRUE(c2.Active()); | ||||
|   container->SetActiveChild(c2); | ||||
|   EXPECT_EQ(container->ActiveChild(), c2); | ||||
|   EXPECT_FALSE(c0->Focused()); | ||||
|   EXPECT_FALSE(c0->Active()); | ||||
|   EXPECT_FALSE(c1->Focused()); | ||||
|   EXPECT_FALSE(c1->Active()); | ||||
|   EXPECT_TRUE(c2->Focused()); | ||||
|   EXPECT_TRUE(c2->Active()); | ||||
|  | ||||
|   container.SetActiveChild(&c0); | ||||
|   EXPECT_EQ(container.ActiveChild(), &c0); | ||||
|   EXPECT_TRUE(c0.Focused()); | ||||
|   EXPECT_TRUE(c0.Active()); | ||||
|   EXPECT_FALSE(c1.Focused()); | ||||
|   EXPECT_FALSE(c1.Active()); | ||||
|   EXPECT_FALSE(c2.Focused()); | ||||
|   EXPECT_FALSE(c2.Active()); | ||||
|   container->SetActiveChild(c0); | ||||
|   EXPECT_EQ(container->ActiveChild(), c0); | ||||
|   EXPECT_TRUE(c0->Focused()); | ||||
|   EXPECT_TRUE(c0->Active()); | ||||
|   EXPECT_FALSE(c1->Focused()); | ||||
|   EXPECT_FALSE(c1->Active()); | ||||
|   EXPECT_FALSE(c2->Focused()); | ||||
|   EXPECT_FALSE(c2->Active()); | ||||
| } | ||||
|  | ||||
| TEST(ContainerTest, TakeFocus) { | ||||
| @@ -214,74 +214,74 @@ TEST(ContainerTest, TakeFocus) { | ||||
|   auto c22 = Container::Horizontal(); | ||||
|   auto c23 = Container::Horizontal(); | ||||
|  | ||||
|   c.Add(&c1); | ||||
|   c.Add(&c2); | ||||
|   c.Add(&c3); | ||||
|   c1.Add(&c11); | ||||
|   c1.Add(&c12); | ||||
|   c1.Add(&c13); | ||||
|   c2.Add(&c21); | ||||
|   c2.Add(&c22); | ||||
|   c2.Add(&c23); | ||||
|   c->Add(c1); | ||||
|   c->Add(c2); | ||||
|   c->Add(c3); | ||||
|   c1->Add(c11); | ||||
|   c1->Add(c12); | ||||
|   c1->Add(c13); | ||||
|   c2->Add(c21); | ||||
|   c2->Add(c22); | ||||
|   c2->Add(c23); | ||||
|  | ||||
|   EXPECT_TRUE(c.Focused()); | ||||
|   EXPECT_TRUE(c1.Focused()); | ||||
|   EXPECT_FALSE(c2.Focused()); | ||||
|   EXPECT_TRUE(c11.Focused()); | ||||
|   EXPECT_FALSE(c12.Focused()); | ||||
|   EXPECT_FALSE(c13.Focused()); | ||||
|   EXPECT_FALSE(c21.Focused()); | ||||
|   EXPECT_FALSE(c22.Focused()); | ||||
|   EXPECT_FALSE(c23.Focused()); | ||||
|   EXPECT_TRUE(c.Active()); | ||||
|   EXPECT_TRUE(c1.Active()); | ||||
|   EXPECT_FALSE(c2.Active()); | ||||
|   EXPECT_TRUE(c11.Active()); | ||||
|   EXPECT_FALSE(c12.Active()); | ||||
|   EXPECT_FALSE(c13.Active()); | ||||
|   EXPECT_TRUE(c21.Active()); | ||||
|   EXPECT_FALSE(c22.Active()); | ||||
|   EXPECT_FALSE(c23.Active()); | ||||
|   EXPECT_TRUE(c->Focused()); | ||||
|   EXPECT_TRUE(c1->Focused()); | ||||
|   EXPECT_FALSE(c2->Focused()); | ||||
|   EXPECT_TRUE(c11->Focused()); | ||||
|   EXPECT_FALSE(c12->Focused()); | ||||
|   EXPECT_FALSE(c13->Focused()); | ||||
|   EXPECT_FALSE(c21->Focused()); | ||||
|   EXPECT_FALSE(c22->Focused()); | ||||
|   EXPECT_FALSE(c23->Focused()); | ||||
|   EXPECT_TRUE(c->Active()); | ||||
|   EXPECT_TRUE(c1->Active()); | ||||
|   EXPECT_FALSE(c2->Active()); | ||||
|   EXPECT_TRUE(c11->Active()); | ||||
|   EXPECT_FALSE(c12->Active()); | ||||
|   EXPECT_FALSE(c13->Active()); | ||||
|   EXPECT_TRUE(c21->Active()); | ||||
|   EXPECT_FALSE(c22->Active()); | ||||
|   EXPECT_FALSE(c23->Active()); | ||||
|  | ||||
|   c22.TakeFocus(); | ||||
|   EXPECT_TRUE(c.Focused()); | ||||
|   EXPECT_FALSE(c1.Focused()); | ||||
|   EXPECT_TRUE(c2.Focused()); | ||||
|   EXPECT_FALSE(c11.Focused()); | ||||
|   EXPECT_FALSE(c12.Focused()); | ||||
|   EXPECT_FALSE(c13.Focused()); | ||||
|   EXPECT_FALSE(c21.Focused()); | ||||
|   EXPECT_TRUE(c22.Focused()); | ||||
|   EXPECT_FALSE(c23.Focused()); | ||||
|   EXPECT_TRUE(c.Active()); | ||||
|   EXPECT_FALSE(c1.Active()); | ||||
|   EXPECT_TRUE(c2.Active()); | ||||
|   EXPECT_TRUE(c11.Active()); | ||||
|   EXPECT_FALSE(c12.Active()); | ||||
|   EXPECT_FALSE(c13.Active()); | ||||
|   EXPECT_FALSE(c21.Active()); | ||||
|   EXPECT_TRUE(c22.Active()); | ||||
|   EXPECT_FALSE(c23.Active()); | ||||
|   c22->TakeFocus(); | ||||
|   EXPECT_TRUE(c->Focused()); | ||||
|   EXPECT_FALSE(c1->Focused()); | ||||
|   EXPECT_TRUE(c2->Focused()); | ||||
|   EXPECT_FALSE(c11->Focused()); | ||||
|   EXPECT_FALSE(c12->Focused()); | ||||
|   EXPECT_FALSE(c13->Focused()); | ||||
|   EXPECT_FALSE(c21->Focused()); | ||||
|   EXPECT_TRUE(c22->Focused()); | ||||
|   EXPECT_FALSE(c23->Focused()); | ||||
|   EXPECT_TRUE(c->Active()); | ||||
|   EXPECT_FALSE(c1->Active()); | ||||
|   EXPECT_TRUE(c2->Active()); | ||||
|   EXPECT_TRUE(c11->Active()); | ||||
|   EXPECT_FALSE(c12->Active()); | ||||
|   EXPECT_FALSE(c13->Active()); | ||||
|   EXPECT_FALSE(c21->Active()); | ||||
|   EXPECT_TRUE(c22->Active()); | ||||
|   EXPECT_FALSE(c23->Active()); | ||||
|  | ||||
|   c1.TakeFocus(); | ||||
|   EXPECT_TRUE(c.Focused()); | ||||
|   EXPECT_TRUE(c1.Focused()); | ||||
|   EXPECT_FALSE(c2.Focused()); | ||||
|   EXPECT_TRUE(c11.Focused()); | ||||
|   EXPECT_FALSE(c12.Focused()); | ||||
|   EXPECT_FALSE(c13.Focused()); | ||||
|   EXPECT_FALSE(c21.Focused()); | ||||
|   EXPECT_FALSE(c22.Focused()); | ||||
|   EXPECT_FALSE(c23.Focused()); | ||||
|   EXPECT_TRUE(c.Active()); | ||||
|   EXPECT_TRUE(c1.Active()); | ||||
|   EXPECT_FALSE(c2.Active()); | ||||
|   EXPECT_TRUE(c11.Active()); | ||||
|   EXPECT_FALSE(c12.Active()); | ||||
|   EXPECT_FALSE(c13.Active()); | ||||
|   EXPECT_FALSE(c21.Active()); | ||||
|   EXPECT_TRUE(c22.Active()); | ||||
|   EXPECT_FALSE(c23.Active()); | ||||
|   c1->TakeFocus(); | ||||
|   EXPECT_TRUE(c->Focused()); | ||||
|   EXPECT_TRUE(c1->Focused()); | ||||
|   EXPECT_FALSE(c2->Focused()); | ||||
|   EXPECT_TRUE(c11->Focused()); | ||||
|   EXPECT_FALSE(c12->Focused()); | ||||
|   EXPECT_FALSE(c13->Focused()); | ||||
|   EXPECT_FALSE(c21->Focused()); | ||||
|   EXPECT_FALSE(c22->Focused()); | ||||
|   EXPECT_FALSE(c23->Focused()); | ||||
|   EXPECT_TRUE(c->Active()); | ||||
|   EXPECT_TRUE(c1->Active()); | ||||
|   EXPECT_FALSE(c2->Active()); | ||||
|   EXPECT_TRUE(c11->Active()); | ||||
|   EXPECT_FALSE(c12->Active()); | ||||
|   EXPECT_FALSE(c13->Active()); | ||||
|   EXPECT_FALSE(c21->Active()); | ||||
|   EXPECT_TRUE(c22->Active()); | ||||
|   EXPECT_FALSE(c23->Active()); | ||||
| } | ||||
|  | ||||
| // Copyright 2020 Arthur Sonzogni. All rights reserved. | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| #include "ftxui/component/event.hpp" | ||||
| #include <utility>  // for move | ||||
|  | ||||
| #include "ftxui/component/mouse.hpp" | ||||
| #include "ftxui/screen/string.hpp" | ||||
| #include "ftxui/component/event.hpp" | ||||
| #include "ftxui/component/mouse.hpp"  // for Mouse | ||||
| #include "ftxui/screen/string.hpp"    // for to_wstring | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
|   | ||||
| @@ -1,39 +1,73 @@ | ||||
| #include <algorithm>  // for max, min | ||||
| #include <memory>     // for shared_ptr | ||||
|  | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for CapturedMouse | ||||
| #include "ftxui/component/event.hpp"  // for Event, Event::ArrowLeft, Event::ArrowRight, Event::Backspace, Event::Custom, Event::Delete, Event::End, Event::Home, Event::Return | ||||
| #include "ftxui/component/input.hpp" | ||||
|  | ||||
| #include <algorithm> | ||||
| #include <memory> | ||||
|  | ||||
| #include "ftxui/component/captured_mouse.hpp" | ||||
| #include "ftxui/component/mouse.hpp" | ||||
| #include "ftxui/component/screen_interactive.hpp" | ||||
| #include "ftxui/component/mouse.hpp"  // for Mouse, Mouse::Left, Mouse::Pressed | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for Component | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| /// @brief An input box for editing text. | ||||
| /// @param content The editable content. | ||||
| /// @param placeholder The text displayed when content is still empty. | ||||
| /// @ingroup component | ||||
| /// @see InputBase | ||||
| /// | ||||
| /// ### Example | ||||
| /// | ||||
| /// ```cpp | ||||
| /// auto screen = ScreenInteractive::FitComponent(); | ||||
| /// std::wstring content= L""; | ||||
| /// std::wstring placeholder = L"placeholder"; | ||||
| /// Component input = Input(&content, &placeholder); | ||||
| /// screen.Loop(input); | ||||
| /// ``` | ||||
| /// | ||||
| /// ### Output | ||||
| /// | ||||
| /// ```bash | ||||
| /// placeholder | ||||
| /// ``` | ||||
| Component Input(std::wstring* content, const std::wstring* placeholder) { | ||||
|   return Make<InputBase>(content, placeholder); | ||||
| } | ||||
|  | ||||
| // static | ||||
| InputBase* InputBase::From(Component component) { | ||||
|   return static_cast<InputBase*>(component.get()); | ||||
| } | ||||
|  | ||||
| InputBase::InputBase(std::wstring* content, const std::wstring* placeholder) | ||||
|     : content_(content), placeholder_(placeholder) {} | ||||
|  | ||||
| // Component implementation. | ||||
| Element Input::Render() { | ||||
|   cursor_position = std::max(0, std::min<int>(content.size(), cursor_position)); | ||||
| Element InputBase::Render() { | ||||
|   cursor_position = | ||||
|       std::max(0, std::min<int>(content_->size(), cursor_position)); | ||||
|   auto main_decorator = flex | size(HEIGHT, EQUAL, 1); | ||||
|   bool is_focused = Focused(); | ||||
|  | ||||
|   // Placeholder. | ||||
|   if (content.size() == 0) { | ||||
|   // placeholder. | ||||
|   if (content_->size() == 0) { | ||||
|     if (is_focused) | ||||
|       return text(placeholder) | focus | dim | inverted | main_decorator | | ||||
|       return text(*placeholder_) | focus | dim | inverted | main_decorator | | ||||
|              reflect(input_box_); | ||||
|     else | ||||
|       return text(placeholder) | dim | main_decorator | reflect(input_box_); | ||||
|       return text(*placeholder_) | dim | main_decorator | reflect(input_box_); | ||||
|   } | ||||
|  | ||||
|   // Not focused. | ||||
|   if (!is_focused) | ||||
|     return text(content) | main_decorator | reflect(input_box_); | ||||
|     return text(*content_) | main_decorator | reflect(input_box_); | ||||
|  | ||||
|   std::wstring part_before_cursor = content.substr(0, cursor_position); | ||||
|   std::wstring part_at_cursor = cursor_position < (int)content.size() | ||||
|                                     ? content.substr(cursor_position, 1) | ||||
|   std::wstring part_before_cursor = content_->substr(0, cursor_position); | ||||
|   std::wstring part_at_cursor = cursor_position < (int)content_->size() | ||||
|                                     ? content_->substr(cursor_position, 1) | ||||
|                                     : L" "; | ||||
|   std::wstring part_after_cursor = cursor_position < (int)content.size() - 1 | ||||
|                                        ? content.substr(cursor_position + 1) | ||||
|   std::wstring part_after_cursor = cursor_position < (int)content_->size() - 1 | ||||
|                                        ? content_->substr(cursor_position + 1) | ||||
|                                        : L""; | ||||
|   auto focused = is_focused ? focus : select; | ||||
|  | ||||
| @@ -47,8 +81,9 @@ Element Input::Render() { | ||||
|   // clang-format on | ||||
| } | ||||
|  | ||||
| bool Input::OnEvent(Event event) { | ||||
|   cursor_position = std::max(0, std::min<int>(content.size(), cursor_position)); | ||||
| bool InputBase::OnEvent(Event event) { | ||||
|   cursor_position = | ||||
|       std::max(0, std::min<int>(content_->size(), cursor_position)); | ||||
|  | ||||
|   if (event.is_mouse()) | ||||
|     return OnMouseEvent(event); | ||||
| @@ -59,7 +94,7 @@ bool Input::OnEvent(Event event) { | ||||
|   if (event == Event::Backspace) { | ||||
|     if (cursor_position == 0) | ||||
|       return false; | ||||
|     content.erase(cursor_position - 1, 1); | ||||
|     content_->erase(cursor_position - 1, 1); | ||||
|     cursor_position--; | ||||
|     on_change(); | ||||
|     return true; | ||||
| @@ -67,9 +102,9 @@ bool Input::OnEvent(Event event) { | ||||
|  | ||||
|   // Delete | ||||
|   if (event == Event::Delete) { | ||||
|     if (cursor_position == int(content.size())) | ||||
|     if (cursor_position == int(content_->size())) | ||||
|       return false; | ||||
|     content.erase(cursor_position, 1); | ||||
|     content_->erase(cursor_position, 1); | ||||
|     on_change(); | ||||
|     return true; | ||||
|   } | ||||
| @@ -89,7 +124,7 @@ bool Input::OnEvent(Event event) { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   if (event == Event::ArrowRight && cursor_position < (int)content.size()) { | ||||
|   if (event == Event::ArrowRight && cursor_position < (int)content_->size()) { | ||||
|     cursor_position++; | ||||
|     return true; | ||||
|   } | ||||
| @@ -100,13 +135,13 @@ bool Input::OnEvent(Event event) { | ||||
|   } | ||||
|  | ||||
|   if (event == Event::End) { | ||||
|     cursor_position = (int)content.size(); | ||||
|     cursor_position = (int)content_->size(); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   // Content | ||||
|   if (event.is_character()) { | ||||
|     content.insert(cursor_position, 1, event.character()); | ||||
|     content_->insert(cursor_position, 1, event.character()); | ||||
|     cursor_position++; | ||||
|     on_change(); | ||||
|     return true; | ||||
| @@ -114,7 +149,7 @@ bool Input::OnEvent(Event event) { | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| bool Input::OnMouseEvent(Event event) { | ||||
| bool InputBase::OnMouseEvent(Event event) { | ||||
|   if (!CaptureMouse(event)) | ||||
|     return false; | ||||
|   if (!input_box_.Contain(event.mouse().x, event.mouse().y)) | ||||
| @@ -127,7 +162,7 @@ bool Input::OnMouseEvent(Event event) { | ||||
|     int new_cursor_position = | ||||
|         cursor_position + event.mouse().x - cursor_box_.x_min; | ||||
|     new_cursor_position = | ||||
|         std::max(0, std::min<int>(content.size(), new_cursor_position)); | ||||
|         std::max(0, std::min<int>(content_->size(), new_cursor_position)); | ||||
|     if (cursor_position != new_cursor_position) { | ||||
|       cursor_position = new_cursor_position; | ||||
|       on_change(); | ||||
|   | ||||
| @@ -1,159 +1,181 @@ | ||||
| #include "ftxui/component/input.hpp" | ||||
| #include "ftxui/component/event.hpp" | ||||
| #include <gtest/gtest-message.h>    // for Message | ||||
| #include <gtest/gtest-test-part.h>  // for TestPartResult | ||||
| #include <memory>                   // for __shared_ptr_access | ||||
|  | ||||
| #include "gtest/gtest.h" | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for ftxui | ||||
| #include "ftxui/component/event.hpp"  // for Event, Event::ArrowLeft, Event::ArrowRight, Event::Backspace, Event::Delete, Event::End, Event::Home | ||||
| #include "ftxui/component/input.hpp" | ||||
| #include "gtest/gtest_pred_impl.h"  // for Test, EXPECT_EQ, SuiteApiResolver, TEST, TestFactoryImpl | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| TEST(InputTest, Init) { | ||||
|   Input input; | ||||
|   std::wstring content; | ||||
|   std::wstring placeholder; | ||||
|   Component input = Input(&content, &placeholder); | ||||
|  | ||||
|   EXPECT_EQ(input.content, L""); | ||||
|   EXPECT_EQ(input.placeholder, L""); | ||||
|   EXPECT_EQ(input.cursor_position, 0); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 0); | ||||
| } | ||||
|  | ||||
| TEST(InputTest, Type) { | ||||
|   Input input; | ||||
|   std::wstring content; | ||||
|   std::wstring placeholder; | ||||
|   Component input = Input(&content, &placeholder); | ||||
|  | ||||
|   input.OnEvent(Event::Character('a')); | ||||
|   EXPECT_EQ(input.content, L"a"); | ||||
|   EXPECT_EQ(input.cursor_position, 1u); | ||||
|   input->OnEvent(Event::Character('a')); | ||||
|   EXPECT_EQ(content, L"a"); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 1u); | ||||
|  | ||||
|   input.OnEvent(Event::Character('b')); | ||||
|   EXPECT_EQ(input.content, L"ab"); | ||||
|   EXPECT_EQ(input.cursor_position, 2u); | ||||
|   input->OnEvent(Event::Character('b')); | ||||
|   EXPECT_EQ(content, L"ab"); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 2u); | ||||
| } | ||||
|  | ||||
| TEST(InputTest, Arrow) { | ||||
|   Input input; | ||||
|   std::wstring content; | ||||
|   std::wstring placeholder; | ||||
|   Component input = Input(&content, &placeholder); | ||||
|  | ||||
|   input.OnEvent(Event::Character('a')); | ||||
|   input.OnEvent(Event::Character('b')); | ||||
|   input.OnEvent(Event::Character('c')); | ||||
|   input->OnEvent(Event::Character('a')); | ||||
|   input->OnEvent(Event::Character('b')); | ||||
|   input->OnEvent(Event::Character('c')); | ||||
|  | ||||
|   EXPECT_EQ(input.cursor_position, 3u); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 3u); | ||||
|  | ||||
|   input.OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(input.cursor_position, 2u); | ||||
|   input->OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 2u); | ||||
|  | ||||
|   input.OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(input.cursor_position, 1u); | ||||
|   input->OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 1u); | ||||
|  | ||||
|   input.OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(input.cursor_position, 0u); | ||||
|   input->OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 0u); | ||||
|  | ||||
|   input.OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(input.cursor_position, 0u); | ||||
|   input->OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 0u); | ||||
|  | ||||
|   input.OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(input.cursor_position, 1u); | ||||
|   input->OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 1u); | ||||
|  | ||||
|   input.OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(input.cursor_position, 2u); | ||||
|   input->OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 2u); | ||||
|  | ||||
|   input.OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(input.cursor_position, 3u); | ||||
|   input->OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 3u); | ||||
|  | ||||
|   input.OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(input.cursor_position, 3u); | ||||
|   input->OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 3u); | ||||
| } | ||||
|  | ||||
| TEST(InputTest, Insert) { | ||||
|   Input input; | ||||
|   std::wstring content; | ||||
|   std::wstring placeholder; | ||||
|   Component input = Input(&content, &placeholder); | ||||
|  | ||||
|   input.OnEvent(Event::Character('a')); | ||||
|   input.OnEvent(Event::Character('b')); | ||||
|   input.OnEvent(Event::Character('c')); | ||||
|   EXPECT_EQ(input.content, L"abc"); | ||||
|   input->OnEvent(Event::Character('a')); | ||||
|   input->OnEvent(Event::Character('b')); | ||||
|   input->OnEvent(Event::Character('c')); | ||||
|   EXPECT_EQ(content, L"abc"); | ||||
|  | ||||
|   input.OnEvent(Event::ArrowLeft); | ||||
|   input.OnEvent(Event::ArrowLeft); | ||||
|   input.OnEvent(Event::Character('-')); | ||||
|   EXPECT_EQ(input.content, L"a-bc"); | ||||
|   input->OnEvent(Event::ArrowLeft); | ||||
|   input->OnEvent(Event::ArrowLeft); | ||||
|   input->OnEvent(Event::Character('-')); | ||||
|   EXPECT_EQ(content, L"a-bc"); | ||||
|  | ||||
|   input.OnEvent(Event::ArrowLeft); | ||||
|   input.OnEvent(Event::Character('-')); | ||||
|   EXPECT_EQ(input.content, L"a--bc"); | ||||
|   input->OnEvent(Event::ArrowLeft); | ||||
|   input->OnEvent(Event::Character('-')); | ||||
|   EXPECT_EQ(content, L"a--bc"); | ||||
|  | ||||
|   input.OnEvent(Event::ArrowLeft); | ||||
|   input.OnEvent(Event::ArrowLeft); | ||||
|   input.OnEvent(Event::ArrowLeft); | ||||
|   input.OnEvent(Event::Character('-')); | ||||
|   EXPECT_EQ(input.content, L"-a--bc"); | ||||
|   input->OnEvent(Event::ArrowLeft); | ||||
|   input->OnEvent(Event::ArrowLeft); | ||||
|   input->OnEvent(Event::ArrowLeft); | ||||
|   input->OnEvent(Event::Character('-')); | ||||
|   EXPECT_EQ(content, L"-a--bc"); | ||||
| } | ||||
|  | ||||
| TEST(InputTest, Home) { | ||||
|   Input input; | ||||
|   std::wstring content; | ||||
|   std::wstring placeholder; | ||||
|   Component input = Input(&content, &placeholder); | ||||
|  | ||||
|   input.OnEvent(Event::Character('a')); | ||||
|   input.OnEvent(Event::Character('b')); | ||||
|   input.OnEvent(Event::Character('c')); | ||||
|   EXPECT_EQ(input.content, L"abc"); | ||||
|   input->OnEvent(Event::Character('a')); | ||||
|   input->OnEvent(Event::Character('b')); | ||||
|   input->OnEvent(Event::Character('c')); | ||||
|   EXPECT_EQ(content, L"abc"); | ||||
|  | ||||
|   EXPECT_EQ(input.cursor_position, 3u); | ||||
|   input.OnEvent(Event::Home); | ||||
|   EXPECT_EQ(input.cursor_position, 0u); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 3u); | ||||
|   input->OnEvent(Event::Home); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 0u); | ||||
|  | ||||
|   input.OnEvent(Event::Character('-')); | ||||
|   EXPECT_EQ(input.content, L"-abc"); | ||||
|   input->OnEvent(Event::Character('-')); | ||||
|   EXPECT_EQ(content, L"-abc"); | ||||
| } | ||||
|  | ||||
| TEST(InputTest, End) { | ||||
|   Input input; | ||||
|   std::wstring content; | ||||
|   std::wstring placeholder; | ||||
|   Component input = Input(&content, &placeholder); | ||||
|  | ||||
|   input.OnEvent(Event::Character('a')); | ||||
|   input.OnEvent(Event::Character('b')); | ||||
|   input.OnEvent(Event::Character('c')); | ||||
|   input->OnEvent(Event::Character('a')); | ||||
|   input->OnEvent(Event::Character('b')); | ||||
|   input->OnEvent(Event::Character('c')); | ||||
|  | ||||
|   input.OnEvent(Event::ArrowLeft); | ||||
|   input.OnEvent(Event::ArrowLeft); | ||||
|   input->OnEvent(Event::ArrowLeft); | ||||
|   input->OnEvent(Event::ArrowLeft); | ||||
|  | ||||
|   EXPECT_EQ(input.cursor_position, 1u); | ||||
|   input.OnEvent(Event::End); | ||||
|   EXPECT_EQ(input.cursor_position, 3u); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 1u); | ||||
|   input->OnEvent(Event::End); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 3u); | ||||
| } | ||||
|  | ||||
| TEST(InputTest, Delete) { | ||||
|   Input input; | ||||
|   std::wstring content; | ||||
|   std::wstring placeholder; | ||||
|   Component input = Input(&content, &placeholder); | ||||
|  | ||||
|   input.OnEvent(Event::Character('a')); | ||||
|   input.OnEvent(Event::Character('b')); | ||||
|   input.OnEvent(Event::Character('c')); | ||||
|   input.OnEvent(Event::ArrowLeft); | ||||
|   input->OnEvent(Event::Character('a')); | ||||
|   input->OnEvent(Event::Character('b')); | ||||
|   input->OnEvent(Event::Character('c')); | ||||
|   input->OnEvent(Event::ArrowLeft); | ||||
|  | ||||
|   EXPECT_EQ(input.content, L"abc"); | ||||
|   EXPECT_EQ(input.cursor_position, 2u); | ||||
|   EXPECT_EQ(content, L"abc"); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 2u); | ||||
|  | ||||
|   input.OnEvent(Event::Delete); | ||||
|   EXPECT_EQ(input.content, L"ab"); | ||||
|   EXPECT_EQ(input.cursor_position, 2u); | ||||
|   input->OnEvent(Event::Delete); | ||||
|   EXPECT_EQ(content, L"ab"); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 2u); | ||||
|  | ||||
|   input.OnEvent(Event::Delete); | ||||
|   EXPECT_EQ(input.content, L"ab"); | ||||
|   EXPECT_EQ(input.cursor_position, 2u); | ||||
|   input->OnEvent(Event::Delete); | ||||
|   EXPECT_EQ(content, L"ab"); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 2u); | ||||
| } | ||||
|  | ||||
| TEST(InputTest, Backspace) { | ||||
|   Input input; | ||||
|   std::wstring content; | ||||
|   std::wstring placeholder; | ||||
|   Component input = Input(&content, &placeholder); | ||||
|  | ||||
|   input.OnEvent(Event::Character('a')); | ||||
|   input.OnEvent(Event::Character('b')); | ||||
|   input.OnEvent(Event::Character('c')); | ||||
|   input.OnEvent(Event::ArrowLeft); | ||||
|   input->OnEvent(Event::Character('a')); | ||||
|   input->OnEvent(Event::Character('b')); | ||||
|   input->OnEvent(Event::Character('c')); | ||||
|   input->OnEvent(Event::ArrowLeft); | ||||
|  | ||||
|   EXPECT_EQ(input.content, L"abc"); | ||||
|   EXPECT_EQ(input.cursor_position, 2u); | ||||
|   EXPECT_EQ(content, L"abc"); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 2u); | ||||
|  | ||||
|   input.OnEvent(Event::Backspace); | ||||
|   EXPECT_EQ(input.content, L"ac"); | ||||
|   EXPECT_EQ(input.cursor_position, 1u); | ||||
|   input->OnEvent(Event::Backspace); | ||||
|   EXPECT_EQ(content, L"ac"); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 1u); | ||||
|  | ||||
|   input.OnEvent(Event::Backspace); | ||||
|   EXPECT_EQ(input.content, L"c"); | ||||
|   EXPECT_EQ(input.cursor_position, 0u); | ||||
|   input->OnEvent(Event::Backspace); | ||||
|   EXPECT_EQ(content, L"c"); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 0u); | ||||
|  | ||||
|   input.OnEvent(Event::Backspace); | ||||
|   EXPECT_EQ(input.content, L"c"); | ||||
|   EXPECT_EQ(input.cursor_position, 0u); | ||||
|   input->OnEvent(Event::Backspace); | ||||
|   EXPECT_EQ(content, L"c"); | ||||
|   EXPECT_EQ(InputBase::From(input)->cursor_position, 0u); | ||||
| } | ||||
|  | ||||
| // 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. | ||||
|   | ||||
| @@ -1,23 +1,63 @@ | ||||
| #include <stddef.h>            // for size_t | ||||
| #include <algorithm>           // for max, min | ||||
| #include <ext/alloc_traits.h>  // for __alloc_traits<>::value_type | ||||
| #include <memory>              // for shared_ptr, allocator_traits<>::value_type | ||||
| #include <utility>             // for move | ||||
|  | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for CapturedMouse | ||||
| #include "ftxui/component/event.hpp"  // for Event, Event::ArrowDown, Event::ArrowUp, Event::Return, Event::Tab, Event::TabReverse | ||||
| #include "ftxui/component/menu.hpp" | ||||
|  | ||||
| #include <stddef.h> | ||||
| #include <algorithm> | ||||
| #include <memory> | ||||
| #include <utility> | ||||
|  | ||||
| #include "ftxui/component/captured_mouse.hpp" | ||||
| #include "ftxui/component/mouse.hpp" | ||||
| #include "ftxui/component/screen_interactive.hpp" | ||||
| #include "ftxui/component/mouse.hpp"  // for Mouse, Mouse::Left, Mouse::Released | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for Component | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| Element Menu::Render() { | ||||
| /// @brief A list of text. The focused element is selected. | ||||
| /// @param entries The list of entries in the menu. | ||||
| /// @param selected The index of the currently selected element. | ||||
| /// @ingroup component | ||||
| /// @see MenuBase | ||||
| /// | ||||
| /// ### Example | ||||
| /// | ||||
| /// ```cpp | ||||
| /// auto screen = ScreenInteractive::TerminalOutput(); | ||||
| /// std::vector<std::wstring> entries = { | ||||
| ///     L"entry 1", | ||||
| ///     L"entry 2", | ||||
| ///     L"entry 3", | ||||
| /// }; | ||||
| /// int selected = 0; | ||||
| /// auto menu = Menu(&entries, &selected); | ||||
| /// screen.Loop(menu); | ||||
| /// ``` | ||||
| /// | ||||
| /// ### Output | ||||
| /// | ||||
| /// ```bash | ||||
| /// > entry 1 | ||||
| ///   entry 2 | ||||
| ///   entry 3 | ||||
| /// ``` | ||||
| Component Menu(const std::vector<std::wstring>* entries, int* selected) { | ||||
|   return Make<MenuBase>(entries, selected); | ||||
| } | ||||
|  | ||||
| // static | ||||
| MenuBase* MenuBase::From(Component component) { | ||||
|   return static_cast<MenuBase*>(component.get()); | ||||
| } | ||||
|  | ||||
| MenuBase::MenuBase(const std::vector<std::wstring>* entries, int* selected) | ||||
|     : entries_(entries), selected_(selected) {} | ||||
|  | ||||
| Element MenuBase::Render() { | ||||
|   Elements elements; | ||||
|   bool is_menu_focused = Focused(); | ||||
|   boxes_.resize(entries.size()); | ||||
|   for (size_t i = 0; i < entries.size(); ++i) { | ||||
|   boxes_.resize(entries_->size()); | ||||
|   for (size_t i = 0; i < entries_->size(); ++i) { | ||||
|     bool is_focused = (focused == int(i)) && is_menu_focused; | ||||
|     bool is_selected = (selected == int(i)); | ||||
|     bool is_selected = (*selected_ == int(i)); | ||||
|  | ||||
|     auto style = is_selected | ||||
|                      ? (is_focused ? selected_focused_style : selected_style) | ||||
| @@ -26,13 +66,13 @@ Element Menu::Render() { | ||||
|                             : is_menu_focused ? focus | ||||
|                                               : select; | ||||
|     auto icon = is_selected ? L"> " : L"  "; | ||||
|     elements.push_back(text(icon + entries[i]) | style | focus_management | | ||||
|     elements.push_back(text(icon + entries_->at(i)) | style | focus_management | | ||||
|                        reflect(boxes_[i])); | ||||
|   } | ||||
|   return vbox(std::move(elements)); | ||||
| } | ||||
|  | ||||
| bool Menu::OnEvent(Event event) { | ||||
| bool MenuBase::OnEvent(Event event) { | ||||
|   if (!CaptureMouse(event)) | ||||
|     return false; | ||||
|   if (event.is_mouse()) | ||||
| @@ -41,20 +81,20 @@ bool Menu::OnEvent(Event event) { | ||||
|   if (!Focused()) | ||||
|     return false; | ||||
|  | ||||
|   int old_selected = selected; | ||||
|   int old_selected = *selected_; | ||||
|   if (event == Event::ArrowUp || event == Event::Character('k')) | ||||
|     selected--; | ||||
|     (*selected_)--; | ||||
|   if (event == Event::ArrowDown || event == Event::Character('j')) | ||||
|     selected++; | ||||
|   if (event == Event::Tab && entries.size()) | ||||
|     selected = (selected + 1) % entries.size(); | ||||
|   if (event == Event::TabReverse && entries.size()) | ||||
|     selected = (selected + entries.size() - 1) % entries.size(); | ||||
|     (*selected_)++; | ||||
|   if (event == Event::Tab && entries_->size()) | ||||
|     *selected_ = (*selected_ + 1) % entries_->size(); | ||||
|   if (event == Event::TabReverse && entries_->size()) | ||||
|     *selected_ = (*selected_ + entries_->size() - 1) % entries_->size(); | ||||
|  | ||||
|   selected = std::max(0, std::min(int(entries.size()) - 1, selected)); | ||||
|   *selected_ = std::max(0, std::min(int(entries_->size()) - 1, *selected_)); | ||||
|  | ||||
|   if (selected != old_selected) { | ||||
|     focused = selected; | ||||
|   if (*selected_ != old_selected) { | ||||
|     focused = *selected_; | ||||
|     on_change(); | ||||
|     return true; | ||||
|   } | ||||
| @@ -67,7 +107,7 @@ bool Menu::OnEvent(Event event) { | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| bool Menu::OnMouseEvent(Event event) { | ||||
| bool MenuBase::OnMouseEvent(Event event) { | ||||
|   if (!CaptureMouse(event)) | ||||
|     return false; | ||||
|   for (int i = 0; i < boxes_.size(); ++i) { | ||||
| @@ -78,8 +118,8 @@ bool Menu::OnMouseEvent(Event event) { | ||||
|     focused = i; | ||||
|     if (event.mouse().button == Mouse::Left && | ||||
|         event.mouse().motion == Mouse::Released) { | ||||
|       if (selected != i) { | ||||
|         selected = i; | ||||
|       if (*selected_ != i) { | ||||
|         *selected_ = i; | ||||
|         on_change(); | ||||
|       } | ||||
|       return true; | ||||
|   | ||||
| @@ -1,36 +1,76 @@ | ||||
| #include <stddef.h>    // for size_t | ||||
| #include <algorithm>   // for max, min | ||||
| #include <functional>  // for function | ||||
| #include <memory>      // for shared_ptr, allocator_traits<>::value_type | ||||
| #include <utility>     // for move | ||||
|  | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for CapturedMouse | ||||
| #include "ftxui/component/event.hpp"  // for Event, Event::ArrowDown, Event::ArrowUp, Event::Return, Event::Tab, Event::TabReverse | ||||
| #include "ftxui/component/mouse.hpp"  // for Mouse, Mouse::Left, Mouse::Pressed | ||||
| #include "ftxui/component/radiobox.hpp" | ||||
|  | ||||
| #include <stddef.h> | ||||
| #include <algorithm> | ||||
| #include <functional> | ||||
| #include <memory> | ||||
| #include <utility> | ||||
|  | ||||
| #include "ftxui/component/captured_mouse.hpp" | ||||
| #include "ftxui/component/mouse.hpp" | ||||
| #include "ftxui/component/screen_interactive.hpp" | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for Component | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| Element RadioBox::Render() { | ||||
| /// @brief A list of element, where only one can be selected. | ||||
| /// @param entries The list of entries in the list. | ||||
| /// @param selected The index of the currently selected element. | ||||
| /// @ingroup component | ||||
| /// @see RadioboxBase | ||||
| /// | ||||
| /// ### Example | ||||
| /// | ||||
| /// ```cpp | ||||
| /// auto screen = ScreenInteractive::TerminalOutput(); | ||||
| /// std::vector<std::wstring> entries = { | ||||
| ///     L"entry 1", | ||||
| ///     L"entry 2", | ||||
| ///     L"entry 3", | ||||
| /// }; | ||||
| /// int selected = 0; | ||||
| /// auto menu = Radiobox(&entries, &selected); | ||||
| /// screen.Loop(menu); | ||||
| /// ``` | ||||
| /// | ||||
| /// ### Output | ||||
| /// | ||||
| /// ```bash | ||||
| /// ◉ entry 1 | ||||
| /// ○ entry 2 | ||||
| /// ○ entry 3 | ||||
| /// ``` | ||||
| Component Radiobox(const std::vector<std::wstring>* entries, int* selected) { | ||||
|   return Make<RadioboxBase>(entries, selected); | ||||
| } | ||||
|  | ||||
| // static | ||||
| RadioboxBase* RadioboxBase::From(Component component) { | ||||
|   return static_cast<RadioboxBase*>(component.get()); | ||||
| } | ||||
|  | ||||
| RadioboxBase::RadioboxBase(const std::vector<std::wstring>* entries, | ||||
|                            int* selected_) | ||||
|     : entries_(entries), selected_(selected_) {} | ||||
|  | ||||
| Element RadioboxBase::Render() { | ||||
|   std::vector<Element> elements; | ||||
|   bool is_focused = Focused(); | ||||
|   boxes_.resize(entries.size()); | ||||
|   for (size_t i = 0; i < entries.size(); ++i) { | ||||
|   boxes_.resize(entries_->size()); | ||||
|   for (size_t i = 0; i < entries_->size(); ++i) { | ||||
|     auto style = | ||||
|         (focused == int(i) && is_focused) ? focused_style : unfocused_style; | ||||
|     auto focus_management = (focused != int(i)) ? nothing | ||||
|                             : is_focused        ? focus | ||||
|                                                 : select; | ||||
|  | ||||
|     const std::wstring& symbol = selected == int(i) ? checked : unchecked; | ||||
|     elements.push_back(hbox(text(symbol), text(entries[i]) | style) | | ||||
|     const std::wstring& symbol = *selected_ == int(i) ? checked : unchecked; | ||||
|     elements.push_back(hbox(text(symbol), text(entries_->at(i)) | style) | | ||||
|                        focus_management | reflect(boxes_[i])); | ||||
|   } | ||||
|   return vbox(std::move(elements)); | ||||
| } | ||||
|  | ||||
| bool RadioBox::OnEvent(Event event) { | ||||
| bool RadioboxBase::OnEvent(Event event) { | ||||
|   if (!CaptureMouse(event)) | ||||
|     return false; | ||||
|   if (event.is_mouse()) | ||||
| @@ -44,12 +84,12 @@ bool RadioBox::OnEvent(Event event) { | ||||
|     new_focused--; | ||||
|   if (event == Event::ArrowDown || event == Event::Character('j')) | ||||
|     new_focused++; | ||||
|   if (event == Event::Tab && entries.size()) | ||||
|     new_focused = (new_focused + 1) % entries.size(); | ||||
|   if (event == Event::TabReverse && entries.size()) | ||||
|     new_focused = (new_focused + entries.size() - 1) % entries.size(); | ||||
|   if (event == Event::Tab && entries_->size()) | ||||
|     new_focused = (new_focused + 1) % entries_->size(); | ||||
|   if (event == Event::TabReverse && entries_->size()) | ||||
|     new_focused = (new_focused + entries_->size() - 1) % entries_->size(); | ||||
|  | ||||
|   new_focused = std::max(0, std::min(int(entries.size()) - 1, new_focused)); | ||||
|   new_focused = std::max(0, std::min(int(entries_->size()) - 1, new_focused)); | ||||
|  | ||||
|   if (focused != new_focused) { | ||||
|     focused = new_focused; | ||||
| @@ -57,14 +97,14 @@ bool RadioBox::OnEvent(Event event) { | ||||
|   } | ||||
|  | ||||
|   if (event == Event::Character(' ') || event == Event::Return) { | ||||
|     selected = focused; | ||||
|     *selected_ = focused; | ||||
|     on_change(); | ||||
|   } | ||||
|  | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| bool RadioBox::OnMouseEvent(Event event) { | ||||
| bool RadioboxBase::OnMouseEvent(Event event) { | ||||
|   if (!CaptureMouse(event)) | ||||
|     return false; | ||||
|   for (int i = 0; i < boxes_.size(); ++i) { | ||||
| @@ -78,8 +118,8 @@ bool RadioBox::OnMouseEvent(Event event) { | ||||
|         event.mouse().motion == Mouse::Pressed) { | ||||
|       cursor_position = i; | ||||
|       TakeFocus(); | ||||
|       if (selected != i) { | ||||
|         selected = i; | ||||
|       if (*selected_ != i) { | ||||
|         *selected_ = i; | ||||
|         on_change(); | ||||
|       } | ||||
|       return true; | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| #include <gtest/gtest-message.h>  // for Message | ||||
| #include <gtest/gtest-test-part.h>  // for TestPartResult, SuiteApiResolver, TestFactoryImpl | ||||
| #include <memory>                   // for __shared_ptr_access, shared_ptr | ||||
|  | ||||
| #include "ftxui/component/event.hpp"  // for Event, Event::ArrowDown, Event::ArrowUp, Event::Tab, Event::TabReverse | ||||
| #include "ftxui/component/event.hpp"  // for Event, Event::Return, Event::ArrowDown, Event::ArrowUp, Event::Tab, Event::TabReverse | ||||
| #include "ftxui/component/mouse.hpp"  // for ftxui | ||||
| #include "ftxui/component/radiobox.hpp" | ||||
| #include "gtest/gtest_pred_impl.h"  // for EXPECT_EQ, Test, TEST | ||||
| @@ -9,76 +10,105 @@ | ||||
| using namespace ftxui; | ||||
|  | ||||
| TEST(RadioboxTest, Navigation) { | ||||
|   RadioBox radiobox; | ||||
|   radiobox.entries = {L"1", L"2", L"3"}; | ||||
|   int selected = 0; | ||||
|   std::vector<std::wstring> entries = {L"1", L"2", L"3"}; | ||||
|   auto radiobox = Radiobox(&entries, &selected); | ||||
|  | ||||
|   // With arrow key. | ||||
|   EXPECT_EQ(radiobox.focused, 0); | ||||
|   radiobox.OnEvent(Event::ArrowDown); | ||||
|   EXPECT_EQ(radiobox.focused, 1); | ||||
|   radiobox.OnEvent(Event::ArrowDown); | ||||
|   EXPECT_EQ(radiobox.focused, 2); | ||||
|   radiobox.OnEvent(Event::ArrowDown); | ||||
|   EXPECT_EQ(radiobox.focused, 2); | ||||
|   radiobox.OnEvent(Event::ArrowUp); | ||||
|   EXPECT_EQ(radiobox.focused, 1); | ||||
|   radiobox.OnEvent(Event::ArrowUp); | ||||
|   EXPECT_EQ(radiobox.focused, 0); | ||||
|   radiobox.OnEvent(Event::ArrowUp); | ||||
|   EXPECT_EQ(radiobox.focused, 0); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|   radiobox->OnEvent(Event::ArrowDown); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   radiobox->OnEvent(Event::ArrowDown); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 2); | ||||
|   radiobox->OnEvent(Event::ArrowDown); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 2); | ||||
|   radiobox->OnEvent(Event::ArrowUp); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   radiobox->OnEvent(Event::ArrowUp); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|   radiobox->OnEvent(Event::ArrowUp); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|  | ||||
|   // With vim like characters. | ||||
|   EXPECT_EQ(radiobox.focused, 0); | ||||
|   radiobox.OnEvent(Event::Character('j')); | ||||
|   EXPECT_EQ(radiobox.focused, 1); | ||||
|   radiobox.OnEvent(Event::Character('j')); | ||||
|   EXPECT_EQ(radiobox.focused, 2); | ||||
|   radiobox.OnEvent(Event::Character('j')); | ||||
|   EXPECT_EQ(radiobox.focused, 2); | ||||
|   radiobox.OnEvent(Event::Character('k')); | ||||
|   EXPECT_EQ(radiobox.focused, 1); | ||||
|   radiobox.OnEvent(Event::Character('k')); | ||||
|   EXPECT_EQ(radiobox.focused, 0); | ||||
|   radiobox.OnEvent(Event::Character('k')); | ||||
|   EXPECT_EQ(radiobox.focused, 0); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|   radiobox->OnEvent(Event::Character('j')); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   radiobox->OnEvent(Event::Character('j')); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 2); | ||||
|   radiobox->OnEvent(Event::Character('j')); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 2); | ||||
|   radiobox->OnEvent(Event::Character('k')); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   radiobox->OnEvent(Event::Character('k')); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|   radiobox->OnEvent(Event::Character('k')); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|  | ||||
|   // With more entries | ||||
|   radiobox.entries = {L"1", L"2", L"3"}; | ||||
|   EXPECT_EQ(radiobox.focused, 0); | ||||
|   radiobox.OnEvent(Event::ArrowDown); | ||||
|   EXPECT_EQ(radiobox.focused, 1); | ||||
|   radiobox.OnEvent(Event::ArrowDown); | ||||
|   EXPECT_EQ(radiobox.focused, 2); | ||||
|   radiobox.OnEvent(Event::ArrowDown); | ||||
|   EXPECT_EQ(radiobox.focused, 2); | ||||
|   radiobox.OnEvent(Event::ArrowUp); | ||||
|   EXPECT_EQ(radiobox.focused, 1); | ||||
|   radiobox.OnEvent(Event::ArrowUp); | ||||
|   EXPECT_EQ(radiobox.focused, 0); | ||||
|   radiobox.OnEvent(Event::ArrowUp); | ||||
|   EXPECT_EQ(radiobox.focused, 0); | ||||
|   entries = {L"1", L"2", L"3"}; | ||||
|   EXPECT_EQ(selected, 0); | ||||
|   radiobox->OnEvent(Event::ArrowDown); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   radiobox->OnEvent(Event::ArrowDown); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 2); | ||||
|   radiobox->OnEvent(Event::ArrowDown); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 2); | ||||
|   radiobox->OnEvent(Event::ArrowUp); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   radiobox->OnEvent(Event::ArrowUp); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|   radiobox->OnEvent(Event::ArrowUp); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|  | ||||
|   // With tab. | ||||
|   EXPECT_EQ(radiobox.focused, 0); | ||||
|   radiobox.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(radiobox.focused, 1); | ||||
|   radiobox.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(radiobox.focused, 2); | ||||
|   radiobox.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(radiobox.focused, 0); | ||||
|   radiobox.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(radiobox.focused, 1); | ||||
|   radiobox.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(radiobox.focused, 2); | ||||
|   radiobox.OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(radiobox.focused, 1); | ||||
|   radiobox.OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(radiobox.focused, 0); | ||||
|   radiobox.OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(radiobox.focused, 2); | ||||
|   radiobox.OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(radiobox.focused, 1); | ||||
|   radiobox.OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|   radiobox->OnEvent(Event::Tab); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   radiobox->OnEvent(Event::Tab); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 2); | ||||
|   radiobox->OnEvent(Event::Tab); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|   radiobox->OnEvent(Event::Tab); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   radiobox->OnEvent(Event::Tab); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 2); | ||||
|   radiobox->OnEvent(Event::TabReverse); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   radiobox->OnEvent(Event::TabReverse); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|   radiobox->OnEvent(Event::TabReverse); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 2); | ||||
|   radiobox->OnEvent(Event::TabReverse); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   radiobox->OnEvent(Event::TabReverse); | ||||
|   radiobox->OnEvent(Event::Return); | ||||
| } | ||||
|  | ||||
| // Copyright 2020 Arthur Sonzogni. All rights reserved. | ||||
|   | ||||
| @@ -1,24 +1,23 @@ | ||||
| #include "ftxui/component/screen_interactive.hpp" | ||||
|  | ||||
| #include <stdio.h>    // for fileno, stdin | ||||
| #include <algorithm>  // for copy, max, min | ||||
| #include <csignal>    // for signal, SIGINT | ||||
| #include <csignal>    // for signal, SIGINT, SIGWINCH | ||||
| #include <cstdlib>    // for exit, NULL | ||||
| #include <iostream>   // for cout, ostream | ||||
| #include <iostream>  // for cout, ostream, basic_ostream, operator<<, endl, flush | ||||
| #include <stack>     // for stack | ||||
| #include <thread>    // for thread | ||||
| #include <utility>   // for move | ||||
| #include <vector>    // for vector | ||||
|  | ||||
| #include "ftxui/component/captured_mouse.hpp"         // for CapturedMouse | ||||
| #include "ftxui/component/component.hpp"              // for Component | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for CapturedMouse, CapturedMouseInterface | ||||
| #include "ftxui/component/component_base.hpp"  // for ComponentBase | ||||
| #include "ftxui/component/event.hpp"           // for Event | ||||
| #include "ftxui/component/mouse.hpp"           // for Mouse | ||||
| #include "ftxui/component/receiver.hpp"               // for ReceiverImpl | ||||
| #include "ftxui/component/terminal_input_parser.hpp"  // for TerminalInputPa... | ||||
| #include "ftxui/component/receiver.hpp"  // for ReceiverImpl, SenderImpl, MakeReceiver | ||||
| #include "ftxui/component/screen_interactive.hpp" | ||||
| #include "ftxui/component/terminal_input_parser.hpp"  // for TerminalInputParser | ||||
| #include "ftxui/dom/node.hpp"                         // for Node, Render | ||||
| #include "ftxui/dom/requirement.hpp"                  // for Requirement | ||||
| #include "ftxui/screen/terminal.hpp"                  // for Terminal::Dimen... | ||||
| #include "ftxui/screen/terminal.hpp"  // for Terminal::Dimensions, Terminal | ||||
|  | ||||
| #if defined(_WIN32) | ||||
| #define DEFINE_CONSOLEV2_PROPERTIES | ||||
| @@ -31,8 +30,8 @@ | ||||
| #error Must be compiled in UNICODE mode | ||||
| #endif | ||||
| #else | ||||
| #include <sys/select.h>  // for select, FD_ISSET | ||||
| #include <termios.h>     // for tcsetattr, tcge... | ||||
| #include <sys/select.h>  // for select, FD_ISSET, FD_SET, FD_ZERO, fd_set | ||||
| #include <termios.h>  // for tcsetattr, termios, tcgetattr, TCSANOW, cc_t, ECHO, ICANON, VMIN, VTIME | ||||
| #include <unistd.h>  // for STDIN_FILENO, read | ||||
| #endif | ||||
|  | ||||
| @@ -110,7 +109,7 @@ void EventListener(std::atomic<bool>* quit, Sender<Event> out) { | ||||
|  | ||||
|   char c; | ||||
|   while (!*quit) { | ||||
|     while(read(STDIN_FILENO, &c, 1), c) | ||||
|     while (read(STDIN_FILENO, &c, 1), c) | ||||
|       parser.Add(c); | ||||
|  | ||||
|     emscripten_sleep(1); | ||||
| @@ -278,7 +277,7 @@ CapturedMouse ScreenInteractive::CaptureMouse() { | ||||
|       [this] { mouse_captured = false; }); | ||||
| } | ||||
|  | ||||
| void ScreenInteractive::Loop(Component* component) { | ||||
| void ScreenInteractive::Loop(Component component) { | ||||
|   // Install a SIGINT handler and restore the old handler on exit. | ||||
|   auto old_sigint_handler = std::signal(SIGINT, OnExit); | ||||
|   on_exit_functions.push( | ||||
| @@ -417,7 +416,7 @@ void ScreenInteractive::Loop(Component* component) { | ||||
|   OnExit(0); | ||||
| } | ||||
|  | ||||
| void ScreenInteractive::Draw(Component* component) { | ||||
| void ScreenInteractive::Draw(Component component) { | ||||
|   auto document = component->Render(); | ||||
|   int dimx = 0; | ||||
|   int dimy = 0; | ||||
|   | ||||
| @@ -1,21 +1,22 @@ | ||||
| #include "ftxui/component/slider.hpp" | ||||
| #include <string>   // for allocator, wstring | ||||
| #include <utility>  // for move | ||||
|  | ||||
| #include <memory> | ||||
| #include <utility> | ||||
|  | ||||
| #include "ftxui/component/captured_mouse.hpp" | ||||
| #include "ftxui/component/mouse.hpp" | ||||
| #include "ftxui/component/screen_interactive.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/screen/box.hpp" | ||||
| #include "ftxui/screen/color.hpp" | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for CapturedMouse | ||||
| #include "ftxui/component/component.hpp"       // for Make, Slider | ||||
| #include "ftxui/component/component_base.hpp"  // for ComponentBase | ||||
| #include "ftxui/component/event.hpp"  // for Event, Event::ArrowLeft, Event::ArrowRight | ||||
| #include "ftxui/component/mouse.hpp"  // for Mouse, Mouse::Left, Mouse::Pressed, Mouse::Released | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for Component | ||||
| #include "ftxui/dom/elements.hpp"  // for Element, text, color, operator|, xflex, gauge, dim, hbox, reflect, underlined, vcenter | ||||
| #include "ftxui/screen/box.hpp"    // for Box | ||||
| #include "ftxui/screen/color.hpp"  // for Color, Color::GrayDark, Color::GrayLight | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| template <class T> | ||||
| class SliderImpl : public Component { | ||||
| class SliderBase : public ComponentBase { | ||||
|  public: | ||||
|   SliderImpl(std::wstring label, T* value, T min, T max, T increment) | ||||
|   SliderBase(std::wstring label, T* value, T min, T max, T increment) | ||||
|       : label_(label), | ||||
|         value_(value), | ||||
|         min_(min), | ||||
| @@ -53,7 +54,7 @@ class SliderImpl : public Component { | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     return Component::OnEvent(event); | ||||
|     return ComponentBase::OnEvent(event); | ||||
|   } | ||||
|  | ||||
|   bool OnMouseEvent(Event event) { | ||||
| @@ -62,8 +63,7 @@ class SliderImpl : public Component { | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     if (box_.Contain(event.mouse().x, event.mouse().y) && | ||||
|         CaptureMouse(event)) { | ||||
|     if (box_.Contain(event.mouse().x, event.mouse().y) && CaptureMouse(event)) { | ||||
|       TakeFocus(); | ||||
|     } | ||||
|  | ||||
| @@ -94,19 +94,40 @@ class SliderImpl : public Component { | ||||
|   CapturedMouse captured_mouse_; | ||||
| }; | ||||
|  | ||||
| /// @brief An horizontal slider. | ||||
| /// @param label The name of the slider. | ||||
| /// @param value The current value of the slider. | ||||
| /// @param min The minimum value. | ||||
| /// @param max The maximum value. | ||||
| /// @param increment The increment when used by the cursor. | ||||
| /// @ingroup component | ||||
| /// | ||||
| /// ### Example | ||||
| /// | ||||
| /// ```cpp | ||||
| /// auto screen = ScreenInteractive::TerminalOutput(); | ||||
| /// int value = 50; | ||||
| /// auto slider = Slider(L"Value:", &value, 0, 100, 1); | ||||
| /// screen.Loop(slider); | ||||
| /// ``` | ||||
| /// | ||||
| /// ### Output | ||||
| /// | ||||
| /// ```bash | ||||
| /// Value:[██████████████████████████                          ] | ||||
| /// ``` | ||||
| template <class T> | ||||
| ComponentPtr Slider(std::wstring label, T* value, T min, T max, T increment) { | ||||
|   return std::make_unique<SliderImpl<T>>(std::move(label), value, min, max, | ||||
|                                          increment); | ||||
| Component Slider(std::wstring label, T* value, T min, T max, T increment) { | ||||
|   return Make<SliderBase<T>>(std::move(label), value, min, max, increment); | ||||
| } | ||||
|  | ||||
| template ComponentPtr Slider(std::wstring label, | ||||
| template Component Slider(std::wstring label, | ||||
|                           int* value, | ||||
|                           int min, | ||||
|                           int max, | ||||
|                           int increment); | ||||
|  | ||||
| template ComponentPtr Slider(std::wstring label, | ||||
| template Component Slider(std::wstring label, | ||||
|                           float* value, | ||||
|                           float min, | ||||
|                           float max, | ||||
|   | ||||
| @@ -1,26 +1,38 @@ | ||||
| #include <stddef.h>   // for size_t | ||||
| #include <algorithm>  // for max, min | ||||
| #include <memory>     // for shared_ptr, alloca... | ||||
| #include <memory>     // for shared_ptr, allocator_traits<>::value_type | ||||
| #include <utility>    // for move | ||||
|  | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for CapturedMouse | ||||
| #include "ftxui/component/mouse.hpp"               // for Mouse, Mouse::Left | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for ScreenInteractive | ||||
| #include "ftxui/component/event.hpp"  // for Event, Event::ArrowLeft, Event::ArrowRight, Event::Return, Event::Tab, Event::TabReverse | ||||
| #include "ftxui/component/mouse.hpp"  // for Mouse, Mouse::Left, Mouse::Pressed | ||||
| #include "ftxui/component/toggle.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| Element Toggle::Render() { | ||||
| Component Toggle(const std::vector<std::wstring>* entries, int* selected) { | ||||
|   return Make<ToggleBase>(entries, selected); | ||||
| } | ||||
|  | ||||
| // static | ||||
| ToggleBase* ToggleBase::From(Component component) { | ||||
|   return static_cast<ToggleBase*>(component.get()); | ||||
| } | ||||
|  | ||||
| ToggleBase::ToggleBase(const std::vector<std::wstring>* entries, int* selected) | ||||
|     : entries_(entries), selected_(selected) {} | ||||
|  | ||||
| Element ToggleBase::Render() { | ||||
|   Elements children; | ||||
|   bool is_toggle_focused = Focused(); | ||||
|   boxes_.resize(entries.size()); | ||||
|   for (size_t i = 0; i < entries.size(); ++i) { | ||||
|   boxes_.resize(entries_->size()); | ||||
|   for (size_t i = 0; i < entries_->size(); ++i) { | ||||
|     // Separator. | ||||
|     if (i != 0) | ||||
|       children.push_back(separator()); | ||||
|  | ||||
|     bool is_focused = (focused == int(i)) && is_toggle_focused; | ||||
|     bool is_selected = (selected == int(i)); | ||||
|     bool is_selected = (*selected_ == int(i)); | ||||
|  | ||||
|     auto style = is_selected | ||||
|                      ? (is_focused ? selected_focused_style : selected_style) | ||||
| @@ -28,30 +40,30 @@ Element Toggle::Render() { | ||||
|     auto focus_management = !is_selected        ? nothing | ||||
|                             : is_toggle_focused ? focus | ||||
|                                                 : select; | ||||
|     children.push_back(text(entries[i]) | style | focus_management | | ||||
|     children.push_back(text(entries_->at(i)) | style | focus_management | | ||||
|                        reflect(boxes_[i])); | ||||
|   } | ||||
|   return hbox(std::move(children)); | ||||
| } | ||||
|  | ||||
| bool Toggle::OnEvent(Event event) { | ||||
| bool ToggleBase::OnEvent(Event event) { | ||||
|   if (event.is_mouse()) | ||||
|     return OnMouseEvent(event); | ||||
|  | ||||
|   int old_selected = selected; | ||||
|   int old_selected = *selected_; | ||||
|   if (event == Event::ArrowLeft || event == Event::Character('h')) | ||||
|     selected--; | ||||
|     (*selected_)--; | ||||
|   if (event == Event::ArrowRight || event == Event::Character('l')) | ||||
|     selected++; | ||||
|   if (event == Event::Tab && entries.size()) | ||||
|     selected = (selected + 1) % entries.size(); | ||||
|   if (event == Event::TabReverse && entries.size()) | ||||
|     selected = (selected + entries.size() - 1) % entries.size(); | ||||
|     (*selected_)++; | ||||
|   if (event == Event::Tab && entries_->size()) | ||||
|     *selected_ = (*selected_ + 1) % entries_->size(); | ||||
|   if (event == Event::TabReverse && entries_->size()) | ||||
|     *selected_ = (*selected_ + entries_->size() - 1) % entries_->size(); | ||||
|  | ||||
|   selected = std::max(0, std::min(int(entries.size()) - 1, selected)); | ||||
|   *selected_ = std::max(0, std::min(int(entries_->size()) - 1, *selected_)); | ||||
|  | ||||
|   if (old_selected != selected) { | ||||
|     focused = selected; | ||||
|   if (old_selected != *selected_) { | ||||
|     focused = *selected_; | ||||
|     on_change(); | ||||
|     return true; | ||||
|   } | ||||
| @@ -64,7 +76,7 @@ bool Toggle::OnEvent(Event event) { | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| bool Toggle::OnMouseEvent(Event event) { | ||||
| bool ToggleBase::OnMouseEvent(Event event) { | ||||
|   if (!CaptureMouse(event)) | ||||
|     return false; | ||||
|   for (int i = 0; i < boxes_.size(); ++i) { | ||||
| @@ -76,8 +88,8 @@ bool Toggle::OnMouseEvent(Event event) { | ||||
|     if (event.mouse().button == Mouse::Left && | ||||
|         event.mouse().motion == Mouse::Pressed) { | ||||
|       TakeFocus(); | ||||
|       if (selected != i) { | ||||
|         selected = i; | ||||
|       if (*selected_ != i) { | ||||
|         *selected_ = i; | ||||
|         on_change(); | ||||
|       } | ||||
|       return true; | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| #include <gtest/gtest-message.h>  // for Message | ||||
| #include <gtest/gtest-test-part.h>  // for TestPartResult, SuiteApiResolver, TestFactoryImpl | ||||
| #include <memory>                   // for __shared_ptr_access, shared_ptr | ||||
|  | ||||
| #include "ftxui/component/event.hpp"  // for Event, Event::ArrowLeft, Event::ArrowRight, Event::Return, Event::Tab, Event::TabReverse | ||||
| #include "ftxui/component/mouse.hpp"  // for ftxui | ||||
| @@ -9,131 +10,136 @@ | ||||
| using namespace ftxui; | ||||
|  | ||||
| TEST(ToggleTest, leftRightArrow) { | ||||
|   Toggle toggle; | ||||
|   std::vector<std::wstring> entries = {L"On", L"Off"}; | ||||
|   int selected = 0; | ||||
|   auto toggle = Toggle(&entries, &selected); | ||||
|  | ||||
|   // With arrow key. | ||||
|   EXPECT_EQ(toggle.selected, 0); | ||||
|   toggle.OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(toggle.selected, 1); | ||||
|   toggle.OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(toggle.selected, 1); | ||||
|   toggle.OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(toggle.selected, 0); | ||||
|   toggle.OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(toggle.selected, 0); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|   toggle->OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   toggle->OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   toggle->OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|   toggle->OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|  | ||||
|   // With vim like characters. | ||||
|   EXPECT_EQ(toggle.selected, 0); | ||||
|   toggle.OnEvent(Event::Character('l')); | ||||
|   EXPECT_EQ(toggle.selected, 1); | ||||
|   toggle.OnEvent(Event::Character('l')); | ||||
|   EXPECT_EQ(toggle.selected, 1); | ||||
|   toggle.OnEvent(Event::Character('h')); | ||||
|   EXPECT_EQ(toggle.selected, 0); | ||||
|   toggle.OnEvent(Event::Character('h')); | ||||
|   EXPECT_EQ(toggle.selected, 0); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|   toggle->OnEvent(Event::Character('l')); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   toggle->OnEvent(Event::Character('l')); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   toggle->OnEvent(Event::Character('h')); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|   toggle->OnEvent(Event::Character('h')); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|  | ||||
|   // With more entries | ||||
|   toggle.entries = {L"1", L"2", L"3"}; | ||||
|   EXPECT_EQ(toggle.selected, 0); | ||||
|   toggle.OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(toggle.selected, 1); | ||||
|   toggle.OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(toggle.selected, 2); | ||||
|   toggle.OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(toggle.selected, 2); | ||||
|   toggle.OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(toggle.selected, 1); | ||||
|   toggle.OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(toggle.selected, 0); | ||||
|   toggle.OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(toggle.selected, 0); | ||||
|   entries = {L"1", L"2", L"3"}; | ||||
|   EXPECT_EQ(selected, 0); | ||||
|   toggle->OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   toggle->OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(selected, 2); | ||||
|   toggle->OnEvent(Event::ArrowRight); | ||||
|   EXPECT_EQ(selected, 2); | ||||
|   toggle->OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   toggle->OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|   toggle->OnEvent(Event::ArrowLeft); | ||||
|   EXPECT_EQ(selected, 0); | ||||
| } | ||||
|  | ||||
| TEST(ToggleTest, Tab) { | ||||
|   Toggle toggle; | ||||
|   toggle.entries = {L"1", L"2", L"3"}; | ||||
|   std::vector<std::wstring> entries = {L"1", L"2", L"3"}; | ||||
|   int selected = 0; | ||||
|   auto toggle = Toggle(&entries, &selected); | ||||
|  | ||||
|   EXPECT_EQ(toggle.selected, 0); | ||||
|   toggle.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(toggle.selected, 1); | ||||
|   toggle.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(toggle.selected, 2); | ||||
|   toggle.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(toggle.selected, 0); | ||||
|   toggle.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(toggle.selected, 1); | ||||
|   toggle.OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(toggle.selected, 2); | ||||
|   toggle.OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(toggle.selected, 1); | ||||
|   toggle.OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(toggle.selected, 0); | ||||
|   toggle.OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(toggle.selected, 2); | ||||
|   toggle.OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(toggle.selected, 1); | ||||
|   toggle.OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|   toggle->OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   toggle->OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(selected, 2); | ||||
|   toggle->OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|   toggle->OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   toggle->OnEvent(Event::Tab); | ||||
|   EXPECT_EQ(selected, 2); | ||||
|   toggle->OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   toggle->OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(selected, 0); | ||||
|   toggle->OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(selected, 2); | ||||
|   toggle->OnEvent(Event::TabReverse); | ||||
|   EXPECT_EQ(selected, 1); | ||||
|   toggle->OnEvent(Event::TabReverse); | ||||
| } | ||||
|  | ||||
| TEST(ToggleTest, OnChange) { | ||||
|   Toggle toggle; | ||||
|   toggle.entries = {L"1", L"2", L"3"}; | ||||
|   std::vector<std::wstring> entries = {L"1", L"2", L"3"}; | ||||
|   int selected = 0; | ||||
|   auto toggle = Toggle(&entries, &selected); | ||||
|  | ||||
|   int counter = 0; | ||||
|   toggle.on_change = [&] { counter++; }; | ||||
|   ToggleBase::From(toggle)->on_change = [&] { counter++; }; | ||||
|  | ||||
|   EXPECT_FALSE(toggle.OnEvent(Event::ArrowLeft));  // Reached far left. | ||||
|   EXPECT_FALSE(toggle->OnEvent(Event::ArrowLeft));  // Reached far left. | ||||
|   EXPECT_EQ(counter, 0); | ||||
|  | ||||
|   EXPECT_TRUE(toggle.OnEvent(Event::ArrowRight));  // [0] -> [1] | ||||
|   EXPECT_TRUE(toggle->OnEvent(Event::ArrowRight));  // [0] -> [1] | ||||
|   EXPECT_EQ(counter, 1); | ||||
|   EXPECT_TRUE(toggle.OnEvent(Event::ArrowRight));  // [1] -> [2] | ||||
|   EXPECT_TRUE(toggle->OnEvent(Event::ArrowRight));  // [1] -> [2] | ||||
|   EXPECT_EQ(counter, 2); | ||||
|  | ||||
|   EXPECT_FALSE(toggle.OnEvent(Event::ArrowRight));  // Reached far right. | ||||
|   EXPECT_FALSE(toggle->OnEvent(Event::ArrowRight));  // Reached far right. | ||||
|   EXPECT_EQ(counter, 2); | ||||
|  | ||||
|   EXPECT_TRUE(toggle.OnEvent(Event::ArrowLeft));  // [2] -> [1] | ||||
|   EXPECT_TRUE(toggle->OnEvent(Event::ArrowLeft));  // [2] -> [1] | ||||
|   EXPECT_EQ(counter, 3); | ||||
|   EXPECT_TRUE(toggle.OnEvent(Event::ArrowLeft));  // [1] -> [0] | ||||
|   EXPECT_TRUE(toggle->OnEvent(Event::ArrowLeft));  // [1] -> [0] | ||||
|   EXPECT_EQ(counter, 4); | ||||
|  | ||||
|   EXPECT_FALSE(toggle.OnEvent(Event::ArrowLeft));  // Reached far left. | ||||
|   EXPECT_FALSE(toggle->OnEvent(Event::ArrowLeft));  // Reached far left. | ||||
|   EXPECT_EQ(counter, 4); | ||||
| } | ||||
|  | ||||
| TEST(ToggleTest, OnEnter) { | ||||
|   Toggle toggle; | ||||
|   toggle.entries = {L"1", L"2", L"3"}; | ||||
|   std::vector<std::wstring> entries = {L"1", L"2", L"3"}; | ||||
|   int selected = 0; | ||||
|   auto toggle = Toggle(&entries, &selected); | ||||
|  | ||||
|   int counter = 0; | ||||
|   toggle.on_enter = [&] { counter++; }; | ||||
|   ToggleBase::From(toggle)->on_enter = [&] { counter++; }; | ||||
|  | ||||
|   EXPECT_FALSE(toggle.OnEvent(Event::ArrowLeft));  // Reached far left. | ||||
|   EXPECT_TRUE(toggle.OnEvent(Event::Return)); | ||||
|   EXPECT_FALSE(toggle->OnEvent(Event::ArrowLeft));  // Reached far left. | ||||
|   EXPECT_TRUE(toggle->OnEvent(Event::Return)); | ||||
|   EXPECT_EQ(counter, 1); | ||||
|  | ||||
|   EXPECT_TRUE(toggle.OnEvent(Event::ArrowRight));  // [0] -> [1] | ||||
|   EXPECT_TRUE(toggle.OnEvent(Event::Return)); | ||||
|   EXPECT_TRUE(toggle->OnEvent(Event::ArrowRight));  // [0] -> [1] | ||||
|   EXPECT_TRUE(toggle->OnEvent(Event::Return)); | ||||
|   EXPECT_EQ(counter, 2); | ||||
|   EXPECT_TRUE(toggle.OnEvent(Event::ArrowRight));  // [1] -> [2] | ||||
|   EXPECT_TRUE(toggle.OnEvent(Event::Return)); | ||||
|   EXPECT_TRUE(toggle->OnEvent(Event::ArrowRight));  // [1] -> [2] | ||||
|   EXPECT_TRUE(toggle->OnEvent(Event::Return)); | ||||
|   EXPECT_EQ(counter, 3); | ||||
|  | ||||
|   EXPECT_FALSE(toggle.OnEvent(Event::ArrowRight));  // Reached far right. | ||||
|   EXPECT_TRUE(toggle.OnEvent(Event::Return)); | ||||
|   EXPECT_FALSE(toggle->OnEvent(Event::ArrowRight));  // Reached far right. | ||||
|   EXPECT_TRUE(toggle->OnEvent(Event::Return)); | ||||
|   EXPECT_EQ(counter, 4); | ||||
|  | ||||
|   EXPECT_TRUE(toggle.OnEvent(Event::ArrowLeft));  // [2] -> [1] | ||||
|   EXPECT_TRUE(toggle.OnEvent(Event::Return)); | ||||
|   EXPECT_TRUE(toggle->OnEvent(Event::ArrowLeft));  // [2] -> [1] | ||||
|   EXPECT_TRUE(toggle->OnEvent(Event::Return)); | ||||
|   EXPECT_EQ(counter, 5); | ||||
|   EXPECT_TRUE(toggle.OnEvent(Event::ArrowLeft));  // [1] -> [0] | ||||
|   EXPECT_TRUE(toggle.OnEvent(Event::Return)); | ||||
|   EXPECT_TRUE(toggle->OnEvent(Event::ArrowLeft));  // [1] -> [0] | ||||
|   EXPECT_TRUE(toggle->OnEvent(Event::Return)); | ||||
|   EXPECT_EQ(counter, 6); | ||||
|  | ||||
|   EXPECT_FALSE(toggle.OnEvent(Event::ArrowLeft));  // Reached far left. | ||||
|   EXPECT_TRUE(toggle.OnEvent(Event::Return)); | ||||
|   EXPECT_FALSE(toggle->OnEvent(Event::ArrowLeft));  // Reached far left. | ||||
|   EXPECT_TRUE(toggle->OnEvent(Event::Return)); | ||||
|   EXPECT_EQ(counter, 7); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,11 @@ | ||||
| #include <memory> | ||||
| #include <memory>   // for make_shared | ||||
| #include <utility>  // for move | ||||
|  | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/dom/node_decorator.hpp" | ||||
| #include "ftxui/screen/box.hpp" | ||||
| #include "ftxui/screen/screen.hpp" | ||||
| #include "ftxui/dom/elements.hpp"        // for Element, unpack, Elements, blink | ||||
| #include "ftxui/dom/node.hpp"            // for Node | ||||
| #include "ftxui/dom/node_decorator.hpp"  // for NodeDecorator | ||||
| #include "ftxui/screen/box.hpp"          // for Box | ||||
| #include "ftxui/screen/screen.hpp"       // for Pixel, Screen | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,11 @@ | ||||
| #include <memory> | ||||
| #include <memory>   // for make_shared | ||||
| #include <utility>  // for move | ||||
|  | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/dom/node_decorator.hpp" | ||||
| #include "ftxui/screen/box.hpp" | ||||
| #include "ftxui/screen/screen.hpp" | ||||
| #include "ftxui/dom/elements.hpp"        // for Element, unpack, Elements, bold | ||||
| #include "ftxui/dom/node.hpp"            // for Node | ||||
| #include "ftxui/dom/node_decorator.hpp"  // for NodeDecorator | ||||
| #include "ftxui/screen/box.hpp"          // for Box | ||||
| #include "ftxui/screen/screen.hpp"       // for Pixel, Screen | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| #include <algorithm>           // for max | ||||
| #include <ext/alloc_traits.h>  // for __alloc_traits<>::value_type | ||||
| #include <iterator>            // for begin, end | ||||
| #include <memory>              // for make_shared, __shared_ptr_access | ||||
| #include <utility>             // for move | ||||
|   | ||||
| @@ -1,10 +1,11 @@ | ||||
| #include <memory> | ||||
| #include <memory>   // for make_shared | ||||
| #include <utility>  // for move | ||||
|  | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/dom/node_decorator.hpp" | ||||
| #include "ftxui/screen/box.hpp" | ||||
| #include "ftxui/screen/screen.hpp" | ||||
| #include "ftxui/dom/elements.hpp"  // for Element, unpack, Elements, clear_under | ||||
| #include "ftxui/dom/node.hpp"      // for Node | ||||
| #include "ftxui/dom/node_decorator.hpp"  // for NodeDecorator | ||||
| #include "ftxui/screen/box.hpp"          // for Box | ||||
| #include "ftxui/screen/screen.hpp"       // for Pixel, Screen | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,11 @@ | ||||
| #include <memory> | ||||
| #include <memory>   // for make_shared | ||||
| #include <utility>  // for move | ||||
|  | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/dom/node_decorator.hpp" | ||||
| #include "ftxui/screen/box.hpp" | ||||
| #include "ftxui/screen/color.hpp" | ||||
| #include "ftxui/screen/screen.hpp" | ||||
| #include "ftxui/dom/elements.hpp"  // for Element, unpack, Decorator, Elements, bgcolor, color | ||||
| #include "ftxui/dom/node_decorator.hpp"  // for NodeDecorator | ||||
| #include "ftxui/screen/box.hpp"          // for Box | ||||
| #include "ftxui/screen/color.hpp"        // for Color | ||||
| #include "ftxui/screen/screen.hpp"       // for Pixel, Screen | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
|  | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include <utility>  // for move | ||||
|  | ||||
| #include "ftxui/dom/elements.hpp"  // for Element, filler, operator|, hbox, flex_grow, vbox, xflex_grow, yflex_grow, align_right, center, hcenter, vcenter | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,11 @@ | ||||
| #include <memory> | ||||
| #include <memory>   // for make_shared | ||||
| #include <utility>  // for move | ||||
|  | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/dom/node_decorator.hpp" | ||||
| #include "ftxui/screen/box.hpp" | ||||
| #include "ftxui/screen/screen.hpp" | ||||
| #include "ftxui/dom/elements.hpp"        // for Element, unpack, Elements, dim | ||||
| #include "ftxui/dom/node.hpp"            // for Node | ||||
| #include "ftxui/dom/node_decorator.hpp"  // for NodeDecorator | ||||
| #include "ftxui/screen/box.hpp"          // for Box | ||||
| #include "ftxui/screen/screen.hpp"       // for Pixel, Screen | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,12 @@ | ||||
| #include <memory> | ||||
| #include <vector> | ||||
| #include <ext/alloc_traits.h>  // for __alloc_traits<>::value_type | ||||
| #include <memory>              // for make_shared, __shared_ptr_access | ||||
| #include <utility>             // for move | ||||
| #include <vector>              // for vector | ||||
|  | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/dom/requirement.hpp" | ||||
| #include "ftxui/screen/box.hpp" | ||||
| #include "ftxui/dom/elements.hpp"  // for Element, unpack, filler, flex, flex_grow, flex_shrink, notflex, xflex, xflex_grow, xflex_shrink, yflex, yflex_grow, yflex_shrink | ||||
| #include "ftxui/dom/node.hpp"      // for Node | ||||
| #include "ftxui/dom/requirement.hpp"  // for Requirement | ||||
| #include "ftxui/screen/box.hpp"       // for Box | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| #include <algorithm>           // for max, min | ||||
| #include <ext/alloc_traits.h>  // for __alloc_traits<>::value_type | ||||
| #include <memory>   // for make_shared, shared_ptr, __shared_ptr_access | ||||
| #include <utility>  // for move | ||||
| #include <vector>   // for vector | ||||
|   | ||||
| @@ -1,9 +1,10 @@ | ||||
| #include <memory> | ||||
| #include <memory>  // for make_shared | ||||
|  | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/dom/requirement.hpp" | ||||
| #include "ftxui/screen/box.hpp" | ||||
| #include "ftxui/screen/screen.hpp" | ||||
| #include "ftxui/dom/elements.hpp"     // for Element, gauge | ||||
| #include "ftxui/dom/node.hpp"         // for Node | ||||
| #include "ftxui/dom/requirement.hpp"  // for Requirement | ||||
| #include "ftxui/screen/box.hpp"       // for Box | ||||
| #include "ftxui/screen/screen.hpp"    // for Screen | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,11 @@ | ||||
| #include <memory> | ||||
| #include <utility> | ||||
| #include <memory>   // for make_shared | ||||
| #include <utility>  // for move | ||||
|  | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/dom/node_decorator.hpp" | ||||
| #include "ftxui/screen/box.hpp" | ||||
| #include "ftxui/screen/screen.hpp" | ||||
| #include "ftxui/dom/elements.hpp"  // for Element, unpack, Elements, inverted | ||||
| #include "ftxui/dom/node.hpp"      // for Node | ||||
| #include "ftxui/dom/node_decorator.hpp"  // for NodeDecorator | ||||
| #include "ftxui/screen/box.hpp"          // for Box | ||||
| #include "ftxui/screen/screen.hpp"       // for Pixel, Screen | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| #include <ext/alloc_traits.h>  // for __alloc_traits<>::value_type | ||||
| #include <memory>              // for __shared_ptr_access | ||||
| #include <vector>              // for vector | ||||
|  | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| #include <memory> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| #include <ext/alloc_traits.h>  // for __alloc_traits<>::value_type | ||||
| #include <memory>              // for make_shared, __shared_ptr_access | ||||
| #include <utility>             // for move | ||||
| #include <vector>              // for vector | ||||
|  | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/dom/requirement.hpp" | ||||
| #include "ftxui/screen/box.hpp" | ||||
| #include "ftxui/dom/elements.hpp"     // for Element, unpack, Decorator, reflect | ||||
| #include "ftxui/dom/node.hpp"         // for Node | ||||
| #include "ftxui/dom/requirement.hpp"  // for Requirement | ||||
| #include "ftxui/screen/box.hpp"       // for Box | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
|   | ||||
| @@ -1,9 +1,10 @@ | ||||
| #include <memory> | ||||
| #include <memory>  // for make_shared | ||||
|  | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/screen/box.hpp" | ||||
| #include "ftxui/screen/screen.hpp" | ||||
| #include "ftxui/dom/elements.hpp"     // for Element, separator | ||||
| #include "ftxui/dom/node.hpp"         // for Node | ||||
| #include "ftxui/dom/requirement.hpp"  // for Requirement | ||||
| #include "ftxui/screen/box.hpp"       // for Box | ||||
| #include "ftxui/screen/screen.hpp"    // for Pixel, Screen | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| #include <stddef.h>            // for size_t | ||||
| #include <algorithm>           // for min, max | ||||
| #include <ext/alloc_traits.h>  // for __alloc_traits<>::value_type | ||||
| #include <memory>              // for make_shared, __shared_ptr_access | ||||
| #include <utility>             // for move | ||||
| #include <vector>              // for vector | ||||
|   | ||||
| @@ -1,9 +1,11 @@ | ||||
| #include <stddef.h> | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include <stddef.h>            // for size_t | ||||
| #include <ext/alloc_traits.h>  // for __alloc_traits<>::value_type | ||||
| #include <memory>              // for allocator, allocator_traits<>::value_type | ||||
| #include <string>              // for basic_string, wstring | ||||
| #include <utility>             // for move | ||||
| #include <vector>              // for vector | ||||
|  | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/dom/elements.hpp"  // for Element, gauge, text, vbox, spinner | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| #include <gtest/gtest-message.h>  // for Message | ||||
| #include <gtest/gtest-test-part.h>  // for TestPartResult | ||||
| #include <gtest/gtest-test-part.h>  // for SuiteApiResolver, TestFactoryImpl, TestPartResult | ||||
| #include <memory>                   // for allocator | ||||
|  | ||||
| #include "ftxui/dom/elements.hpp"   // for text, Element, operator|, border | ||||
| #include "ftxui/dom/node.hpp"       // for Render | ||||
| #include "ftxui/screen/box.hpp"     // for ftxui | ||||
| #include "ftxui/screen/screen.hpp"  // for Screen | ||||
| #include "gtest/gtest_pred_impl.h"  // for Test, SuiteApiResolver, EXPECT_EQ | ||||
| #include "gtest/gtest_pred_impl.h"  // for Test, EXPECT_EQ, TEST | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,11 @@ | ||||
| #include <memory> | ||||
| #include <utility> | ||||
| #include <memory>   // for make_shared | ||||
| #include <utility>  // for move | ||||
|  | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/dom/node_decorator.hpp" | ||||
| #include "ftxui/screen/box.hpp" | ||||
| #include "ftxui/screen/screen.hpp" | ||||
| #include "ftxui/dom/elements.hpp"  // for Element, unpack, Elements, underlined | ||||
| #include "ftxui/dom/node.hpp"      // for Node | ||||
| #include "ftxui/dom/node_decorator.hpp"  // for NodeDecorator | ||||
| #include "ftxui/screen/box.hpp"          // for Box | ||||
| #include "ftxui/screen/screen.hpp"       // for Pixel, Screen | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| #include <algorithm>           // for min | ||||
| #include <ext/alloc_traits.h>  // for __alloc_traits<>::value_type | ||||
| #include <iostream>  // for operator<<, basic_ostream, wstringstream, stringstream, flush, cout, ostream | ||||
| #include <sstream>   // IWYU pragma: keep | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
|  | ||||
| // Copyright 2020 Arthur Sonzogni. All rights reserved. | ||||
| // 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. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 ArthurSonzogni
					ArthurSonzogni