From a6040bc3607ef2c8365b38b0ebfbe4edfb87cbdf Mon Sep 17 00:00:00 2001 From: Arthur Sonzogni Date: Sat, 12 Jan 2019 22:25:49 +0100 Subject: [PATCH] Add CheckBox. --- examples/component/CMakeLists.txt | 5 +- examples/component/checkbox.cpp | 31 +++++++++ examples/component/gallery.cpp | 56 ++++++++++++++++ examples/component/tab.cpp | 44 ------------- examples/component/tab_horizontal.cpp | 66 +++++++++++++++++++ examples/component/tab_vertical.cpp | 66 +++++++++++++++++++ examples/component/toggle.cpp | 36 +++++----- ftxui/CMakeLists.txt | 1 + ftxui/include/ftxui/component/checkbox.hpp | 34 ++++++++++ ftxui/include/ftxui/component/component.hpp | 1 - ftxui/include/ftxui/component/container.hpp | 21 ++++-- ftxui/include/ftxui/component/delegate.hpp | 13 ---- ftxui/include/ftxui/component/menu.hpp | 2 +- ftxui/include/ftxui/component/toggle.hpp | 4 +- ftxui/src/ftxui/component/checkbox.cpp | 20 ++++++ ftxui/src/ftxui/component/component.cpp | 3 + ftxui/src/ftxui/component/container.cpp | 49 ++++++++++++-- ftxui/src/ftxui/component/menu.cpp | 6 +- .../ftxui/component/screen_interactive.cpp | 5 +- ftxui/src/ftxui/component/toggle.cpp | 14 ++-- ftxui/src/ftxui/screen/screen.cpp | 2 +- 21 files changed, 371 insertions(+), 108 deletions(-) create mode 100644 examples/component/checkbox.cpp create mode 100644 examples/component/gallery.cpp delete mode 100644 examples/component/tab.cpp create mode 100644 examples/component/tab_horizontal.cpp create mode 100644 examples/component/tab_vertical.cpp create mode 100644 ftxui/include/ftxui/component/checkbox.hpp delete mode 100644 ftxui/include/ftxui/component/delegate.hpp create mode 100644 ftxui/src/ftxui/component/checkbox.cpp diff --git a/examples/component/CMakeLists.txt b/examples/component/CMakeLists.txt index 9f2f9f5..6ed74d9 100644 --- a/examples/component/CMakeLists.txt +++ b/examples/component/CMakeLists.txt @@ -4,9 +4,12 @@ function(example name) target_link_libraries(${name} PUBLIC component) endfunction(example) +example(gallery) example(input) example(menu) example(menu2) example(menu_style) example(toggle) -example(tab) +example(tab_horizontal) +example(tab_vertical) +example(checkbox) diff --git a/examples/component/checkbox.cpp b/examples/component/checkbox.cpp new file mode 100644 index 0000000..f44366b --- /dev/null +++ b/examples/component/checkbox.cpp @@ -0,0 +1,31 @@ +#include "ftxui/component/checkbox.hpp" +#include "ftxui/component/component.hpp" +#include "ftxui/component/container.hpp" +#include "ftxui/component/screen_interactive.hpp" + +using namespace ftxui; + +class MyComponent : public Component { + private: + CheckBox box_1_; + CheckBox box_2_; + CheckBox box_3_; + Container container_ = Container::Vertical(); + 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"; + } +}; + +int main(int argc, const char *argv[]) { + auto screen = ScreenInteractive::TerminalOutput(); + MyComponent component; + screen.Loop(&component); + return 0; +} diff --git a/examples/component/gallery.cpp b/examples/component/gallery.cpp new file mode 100644 index 0000000..f489c0f --- /dev/null +++ b/examples/component/gallery.cpp @@ -0,0 +1,56 @@ +#include "ftxui/component/container.hpp" +#include "ftxui/component/input.hpp" +#include "ftxui/component/menu.hpp" +#include "ftxui/component/screen_interactive.hpp" +#include "ftxui/component/toggle.hpp" + +using namespace ftxui; + +class MyComponent : public Component { + Container container = Container::Vertical(); + Menu menu; + Input input; + Toggle toggle; + + public: + MyComponent() { + Add(&container); + menu.entries = { + L"Browse the web", + L"Meditate", + L"Sleep", + L"Eat", + }; + container.Add(&menu); + + toggle.entries = { + L"Browse the web", + L"Meditate", + L"Sleep", + L"Eat", + }; + container.Add(&toggle); + + input.placeholder = L"Input placeholder"; + container.Add(&input); + } + + Element Render() override { + return + vbox( + hbox(text(L"menu") | size(10,1), separator(), menu.Render()), + separator(), + hbox(text(L"toggle") | size(10,1), separator(), toggle.Render()), + separator(), + hbox(text(L"input") | size(10,1), separator(), input.Render()) + ) | frame; + } +}; + +int main(int argc, const char* argv[]) { + auto screen = ScreenInteractive::TerminalOutput(); + MyComponent component; + screen.Loop(&component); + + return 0; +} diff --git a/examples/component/tab.cpp b/examples/component/tab.cpp deleted file mode 100644 index 3b112d8..0000000 --- a/examples/component/tab.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include - -#include "ftxui/component/container.hpp" -#include "ftxui/component/menu.hpp" -#include "ftxui/component/screen_interactive.hpp" -#include "ftxui/component/toggle.hpp" -#include "ftxui/screen/string.hpp" - -using namespace ftxui; - -class MyComponent : public Component { - public: - MyComponent() { - Add(&container); - container.Add(&toggle); - container.Add(&menu); - - toggle.options = {L" left ", L" middle ", L" end "}; - menu.entries = {L" top ", L" middle ", L" bottom "}; - } - - std::function on_enter = [](){}; - private: - Container container = Container::Vertical(); - Toggle toggle; - Menu menu; - - Element Render() override { - return - vbox( - hbox(frame(toggle.Render()), filler()), - frame(menu.Render())); - } -}; - - -int main(int argc, const char *argv[]) -{ - auto screen = ScreenInteractive::TerminalOutput(); - MyComponent component; - component.on_enter = screen.ExitLoopClosure(); - screen.Loop(&component); -} diff --git a/examples/component/tab_horizontal.cpp b/examples/component/tab_horizontal.cpp new file mode 100644 index 0000000..95b7f55 --- /dev/null +++ b/examples/component/tab_horizontal.cpp @@ -0,0 +1,66 @@ +#include +#include + +#include "ftxui/component/container.hpp" +#include "ftxui/component/menu.hpp" +#include "ftxui/component/screen_interactive.hpp" +#include "ftxui/component/toggle.hpp" +#include "ftxui/screen/string.hpp" + +using namespace ftxui; + +class MyComponent : public Component { + public: + MyComponent() { + Add(&container_); + container_.Add(&toggle_); + + toggle_.entries = { + L"menu_1", + L"menu_2", + L"menu_3", + }; + + container_.Add(&tab_container_); + + menu_1_.entries = { + L"Forest", + L"Water", + L"I don't know" + }; + tab_container_.Add(&menu_1_); + + menu_2_.entries = { + L"Hello", + L"Hi", + L"Hay", + }; + tab_container_.Add(&menu_2_); + + menu_3_.entries = { + L"Table", + L"Nothing", + L"Is", + L"Empty", + }; + tab_container_.Add(&menu_3_); + } + + std::function on_enter = [](){}; + private: + Toggle toggle_; + Container container_ = Container::Vertical(); + Container tab_container_ = Container::Tab(&(toggle_.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); +} diff --git a/examples/component/tab_vertical.cpp b/examples/component/tab_vertical.cpp new file mode 100644 index 0000000..4cce543 --- /dev/null +++ b/examples/component/tab_vertical.cpp @@ -0,0 +1,66 @@ +#include +#include + +#include "ftxui/component/container.hpp" +#include "ftxui/component/menu.hpp" +#include "ftxui/component/screen_interactive.hpp" +#include "ftxui/component/toggle.hpp" +#include "ftxui/screen/string.hpp" + +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", + }; + + container_.Add(&tab_container_); + + menu_1_.entries = { + L"Forest", + L"Water", + L"I don't know" + }; + tab_container_.Add(&menu_1_); + + menu_2_.entries = { + L"Hello", + L"Hi", + L"Hay", + }; + tab_container_.Add(&menu_2_); + + menu_3_.entries = { + L"Table", + L"Nothing", + L"Is", + L"Empty", + }; + tab_container_.Add(&menu_3_); + } + + std::function 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); +} diff --git a/examples/component/toggle.cpp b/examples/component/toggle.cpp index 84ecb1c..5c8ef75 100644 --- a/examples/component/toggle.cpp +++ b/examples/component/toggle.cpp @@ -12,36 +12,36 @@ 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); + Add(&container_); + container_.Add(&toggle_1_); + container_.Add(&toggle_2_); + container_.Add(&toggle_3_); + container_.Add(&toggle_4_); - toggle_1.options = {L"On", L"Off"}; - toggle_2.options = {L"Enabled", L"Disabled"}; - toggle_3.options = {L"10€", L"0€"}; - toggle_4.options = {L"Nothing", L"One element", L"Several elements"}; + 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 on_enter = []() {}; private: - Container container = Container::Vertical(); - Toggle toggle_1; - Toggle toggle_2; - Toggle toggle_3; - Toggle toggle_4; + Container container_ = Container::Vertical(); + Toggle toggle_1_; + Toggle toggle_2_; + Toggle toggle_3_; + Toggle toggle_4_; 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()) ); } }; diff --git a/ftxui/CMakeLists.txt b/ftxui/CMakeLists.txt index 075a254..614b7c6 100644 --- a/ftxui/CMakeLists.txt +++ b/ftxui/CMakeLists.txt @@ -30,6 +30,7 @@ add_library(dom ) add_library(component + src/ftxui/component/checkbox.cpp src/ftxui/component/component.cpp src/ftxui/component/container.cpp src/ftxui/component/event.cpp diff --git a/ftxui/include/ftxui/component/checkbox.hpp b/ftxui/include/ftxui/component/checkbox.hpp new file mode 100644 index 0000000..f19e209 --- /dev/null +++ b/ftxui/include/ftxui/component/checkbox.hpp @@ -0,0 +1,34 @@ +#ifndef FTXUI_COMPONENT_CHECKBOX_HPP +#define FTXUI_COMPONENT_CHECKBOX_HPP + +#include "ftxui/component/component.hpp" +#include + +namespace ftxui { + +class CheckBox : public Component { + public: + // Constructor. + CheckBox() = default; + ~CheckBox() override = default; + + bool state = false; + std::wstring label = L"label"; + + std::wstring checked = L"[X] "; + std::wstring unchecked = L"[ ] "; + + // State update callback. + std::function on_change = [](){}; + + // Component implementation. + Element Render() override; + bool OnEvent(Event) override; + + private: + int cursor_position = 0; +}; + +} // namespace ftxui + +#endif /* end of include guard: FTXUI_COMPONENT_CHECKBOX_HPP */ diff --git a/ftxui/include/ftxui/component/component.hpp b/ftxui/include/ftxui/component/component.hpp index c64d99d..89846e7 100644 --- a/ftxui/include/ftxui/component/component.hpp +++ b/ftxui/include/ftxui/component/component.hpp @@ -1,7 +1,6 @@ #ifndef FTXUI_COMPONENT_COMPONENT_HPP #define FTXUI_COMPONENT_COMPONENT_HPP -#include "ftxui/component/delegate.hpp" #include "ftxui/component/event.hpp" #include "ftxui/dom/elements.hpp" diff --git a/ftxui/include/ftxui/component/container.hpp b/ftxui/include/ftxui/component/container.hpp index 2e9d970..69628b5 100644 --- a/ftxui/include/ftxui/component/container.hpp +++ b/ftxui/include/ftxui/component/container.hpp @@ -13,22 +13,31 @@ class Container : public Component { public: static Container Vertical(); static Container Horizontal(); + static Container Tab(size_t* selector); ~Container() override = default; // Component override. bool OnEvent(Event event) override; + Element Render() override; Component* ActiveChild() override; + protected: // Handlers - using Handler = bool (Container::*)(Event); - Handler handler_; - bool Vertical(Event event); - bool Horizontal(Event event); + using EventHandler = bool (Container::*)(Event); + bool VerticalEvent(Event event); + bool HorizontalEvent(Event event); + bool TabEvent(Event event) { return false; } + EventHandler event_handler_; + + using RenderHandler = Element (Container::*)(); + Element VerticalRender(); + Element HorizontalRender(); + Element TabRender(); + RenderHandler render_handler_; size_t selected_ = 0; - - Container(Handler); + size_t* selector_ = &selected_; }; } // namespace ftxui diff --git a/ftxui/include/ftxui/component/delegate.hpp b/ftxui/include/ftxui/component/delegate.hpp deleted file mode 100644 index beb72f0..0000000 --- a/ftxui/include/ftxui/component/delegate.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef FTXUI_COMPONENT_DELEGATE_HPP -#define FTXUI_COMPONENT_DELEGATE_HPP - -#include "ftxui/dom/elements.hpp" - -namespace ftxui { - -class Component; - - -} // namespace ftxui - -#endif /* end of include guard: FTXUI_COMPONENT_DELEGATE_HPP */ diff --git a/ftxui/include/ftxui/component/menu.hpp b/ftxui/include/ftxui/component/menu.hpp index 1020194..8f4d102 100644 --- a/ftxui/include/ftxui/component/menu.hpp +++ b/ftxui/include/ftxui/component/menu.hpp @@ -15,7 +15,7 @@ class Menu : public Component { // State. std::vector entries = {}; - int selected = 0; + size_t selected = 0; Decorator active_style = inverted; Decorator selected_style = bold; diff --git a/ftxui/include/ftxui/component/toggle.hpp b/ftxui/include/ftxui/component/toggle.hpp index 5d2628b..659d2e2 100644 --- a/ftxui/include/ftxui/component/toggle.hpp +++ b/ftxui/include/ftxui/component/toggle.hpp @@ -13,8 +13,8 @@ class Toggle : public Component { ~Toggle() override = default; // State. - size_t activated = 0; - std::vector options = {L"On", L"Off"}; + size_t selected = 0; + std::vector entries = {L"On", L"Off"}; // Callback. std::function on_change = [](){}; diff --git a/ftxui/src/ftxui/component/checkbox.cpp b/ftxui/src/ftxui/component/checkbox.cpp new file mode 100644 index 0000000..a879a06 --- /dev/null +++ b/ftxui/src/ftxui/component/checkbox.cpp @@ -0,0 +1,20 @@ +#include "ftxui/component/checkbox.hpp" +#include + +namespace ftxui { + +Element CheckBox::Render() { + auto style = Focused() ? bold : nothing; + return text((state ? checked : unchecked) + label) | style; +} + +bool CheckBox::OnEvent(Event event) { + if (event == Event::Character(' ') || event == Event::Return) { + state = !state; + on_change(); + return true; + } + return false; +} + +} // namespace ftxui diff --git a/ftxui/src/ftxui/component/component.cpp b/ftxui/src/ftxui/component/component.cpp index a09a107..a980e97 100644 --- a/ftxui/src/ftxui/component/component.cpp +++ b/ftxui/src/ftxui/component/component.cpp @@ -35,6 +35,9 @@ Component* Component::ActiveChild() { } Element Component::Render() { + if (children_.size() == 1) + return children_.front()->Render(); + return text(L"Not implemented component"); } diff --git a/ftxui/src/ftxui/component/container.cpp b/ftxui/src/ftxui/component/container.cpp index 19d0a3b..fad00d1 100644 --- a/ftxui/src/ftxui/component/container.cpp +++ b/ftxui/src/ftxui/component/container.cpp @@ -4,15 +4,28 @@ namespace ftxui { // static Container Container::Horizontal() { - return Container(&Container::Horizontal); + Container container; + container.event_handler_ = &Container::HorizontalEvent; + container.render_handler_ = &Container::HorizontalRender; + return container; } // static Container Container::Vertical() { - return Container(&Container::Vertical); + Container container; + container.event_handler_ = &Container::VerticalEvent; + container.render_handler_ = &Container::VerticalRender; + return container; } -Container::Container(Container::Handler handler) : handler_(handler) {} +// static +Container Container::Tab(size_t* selector) { + Container container; + container.event_handler_ = &Container::TabEvent; + container.render_handler_ = &Container::TabRender; + container.selector_ = selector; + return container; +} bool Container::OnEvent(Event event) { if (!Focused()) @@ -21,14 +34,14 @@ bool Container::OnEvent(Event event) { if (ActiveChild()->OnEvent(event)) return true; - return (this->*handler_)(event); + return (this->*event_handler_)(event); } Component* Container::ActiveChild() { - return children_[selected_ % children_.size()]; + return children_[*selector_ % children_.size()]; } -bool Container::Vertical(Event event) { +bool Container::VerticalEvent(Event event) { selected_ %= children_.size(); // Left pressed ? if (event == Event::ArrowUp || event == Event::Character('k')) { @@ -49,7 +62,7 @@ bool Container::Vertical(Event event) { return false; } -bool Container::Horizontal(Event event) { +bool Container::HorizontalEvent(Event event) { selected_ %= children_.size(); // Left pressed ? if (event == Event::ArrowLeft || event == Event::Character('h')) { @@ -70,4 +83,26 @@ bool Container::Horizontal(Event event) { return false; } +Element Container::Render() { + return (this->*render_handler_)(); +} + +Element Container::VerticalRender() { + Elements elements; + for(auto& it : children_) + elements.push_back(it->Render()); + return vbox(std::move(elements)); +} + +Element Container::HorizontalRender() { + Elements elements; + for(auto& it : children_) + elements.push_back(it->Render()); + return hbox(std::move(elements)); +} + +Element Container::TabRender() { + return ActiveChild()->Render(); +} + } // namespace ftxui diff --git a/ftxui/src/ftxui/component/menu.cpp b/ftxui/src/ftxui/component/menu.cpp index 848460b..a703bc2 100644 --- a/ftxui/src/ftxui/component/menu.cpp +++ b/ftxui/src/ftxui/component/menu.cpp @@ -8,7 +8,7 @@ Element Menu::Render() { std::vector elements; bool focused = Focused(); for (size_t i = 0; i < entries.size(); ++i) { - if (size_t(selected) == i) { + if (selected == i) { if (focused) elements.push_back(active_style(text(L"> " + entries[i]))); else @@ -25,12 +25,12 @@ bool Menu::OnEvent(Event event) { if (!Focused()) return false; - int new_selected = selected; + size_t new_selected = selected; if (event == Event::ArrowUp || event == Event::Character('k')) new_selected--; if (event == Event::ArrowDown || event == Event::Character('j')) new_selected++; - new_selected = std::max(0, std::min(int(entries.size())-1, new_selected)); + new_selected = std::max(size_t(0), std::min(entries.size()-size_t(1), new_selected)); if (selected != new_selected) { selected = new_selected; diff --git a/ftxui/src/ftxui/component/screen_interactive.cpp b/ftxui/src/ftxui/component/screen_interactive.cpp index c3fa104..7f49b15 100644 --- a/ftxui/src/ftxui/component/screen_interactive.cpp +++ b/ftxui/src/ftxui/component/screen_interactive.cpp @@ -5,7 +5,6 @@ #include #include #include "ftxui/component/component.hpp" -#include "ftxui/component/delegate.hpp" #include "ftxui/screen/terminal.hpp" namespace ftxui { @@ -87,9 +86,9 @@ void ScreenInteractive::Loop(Component* component) { std::string reset_position; while (!quit_) { + reset_position = ResetPosition(); Draw(component); std::cout << reset_position << ToString() << std::flush; - reset_position = ResetPosition(); Clear(); component->OnEvent(GetEvent()); } @@ -122,10 +121,8 @@ void ScreenInteractive::Draw(Component* component) { } if (dimx != dimx_ || dimy != dimy_) { - std::cerr << dimx_ << " " << dimy_ << std::endl; dimx_ = dimx; dimy_ = dimy; - std::cerr << dimx_ << " " << dimy_ << std::endl; pixels_ = std::vector>( dimy, std::vector(dimx)); } diff --git a/ftxui/src/ftxui/component/toggle.cpp b/ftxui/src/ftxui/component/toggle.cpp index f9a4348..1784ac8 100644 --- a/ftxui/src/ftxui/component/toggle.cpp +++ b/ftxui/src/ftxui/component/toggle.cpp @@ -6,29 +6,29 @@ Element Toggle::Render() { auto highlight = Focused() ? inverted : bold; Elements children; - for(size_t i = 0; i 0 && + if (selected > 0 && (event == Event::ArrowLeft || event == Event::Character('h'))) { - activated--; + selected--; on_change(); return true; } - if (activated < options.size() - 1 && + if (selected < entries.size() - 1 && (event == Event::ArrowRight || event == Event::Character('l'))) { - activated++; + selected++; on_change(); return true; } diff --git a/ftxui/src/ftxui/screen/screen.cpp b/ftxui/src/ftxui/screen/screen.cpp index 98af945..5d2ff01 100644 --- a/ftxui/src/ftxui/screen/screen.cpp +++ b/ftxui/src/ftxui/screen/screen.cpp @@ -94,7 +94,7 @@ Screen Screen::TerminalOutput(std::unique_ptr& element) { std::string Screen::ResetPosition() { std::stringstream ss; - //ss << '\r'; + ss << '\r'; for (size_t y = 1; y < dimy_; ++y) { ss << "\e[2K\r\e[1A"; }