diff --git a/.github/workflows/linux-clang.yaml b/.github/workflows/linux-clang.yaml index 2b3a098..d86d0d3 100644 --- a/.github/workflows/linux-clang.yaml +++ b/.github/workflows/linux-clang.yaml @@ -16,7 +16,7 @@ jobs: mkdir build; cd build; cmake .. - -DCMAKE_CXX_COMPILER=clang++-9 + -DCMAKE_CXX_COMPILER=clang++ -DFTXUI_BUILD_TESTS=ON; cmake --build . --config Release; diff --git a/CMakeLists.txt b/CMakeLists.txt index c5cbc4f..ffa8ca1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,7 @@ add_library(component STATIC include/ftxui/component/screen_interactive.hpp include/ftxui/component/toggle.hpp src/ftxui/component/button.cpp + src/ftxui/component/catch_event.cpp src/ftxui/component/checkbox.cpp src/ftxui/component/component.cpp src/ftxui/component/container.cpp diff --git a/examples/component/button.cpp b/examples/component/button.cpp index 5bc7852..c632caa 100644 --- a/examples/component/button.cpp +++ b/examples/component/button.cpp @@ -14,8 +14,10 @@ int main(int argc, const char* argv[]) { // The tree of components. This defines how to navigate using the keyboard. auto buttons = Container::Horizontal({ - Button("Decrease", [&] { value--; }), - Button("Increase", [&] { value++; }), + Button( + "[Decrease]", [&] { value--; }, false), + Button( + "[Increase]", [&] { value++; }, false), }); // Modify the way to render them on screen: diff --git a/examples/util/print_key_press.cpp b/examples/util/print_key_press.cpp index 02a13b3..bd825b5 100644 --- a/examples/util/print_key_press.cpp +++ b/examples/util/print_key_press.cpp @@ -2,19 +2,19 @@ // Use of this source code is governed by the MIT license that can be found in // the LICENSE file. -#include // for size_t -#include // for max -#include // for Make -#include // for ScreenInteractive -#include // for allocator, operator+, wstring, char_traits, to_wstring, string +#include // for size_t +#include // for max +#include // for shared_ptr +#include // for allocator, char_traits, operator+, wstring, basic_string, to_wstring, string #include // for move #include // for vector #include "ftxui/component/captured_mouse.hpp" // for ftxui -#include "ftxui/component/component_base.hpp" // for ComponentBase +#include "ftxui/component/component.hpp" // for CatchEvent, Renderer #include "ftxui/component/event.hpp" // for Event #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 +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include "ftxui/dom/elements.hpp" // for text, vbox, window, Element, Elements using namespace ftxui; @@ -72,28 +72,22 @@ std::wstring Stringify(Event event) { return out; } -class DrawKey : public ComponentBase { - public: - ~DrawKey() override = default; - - Element Render() override { - Elements children; - for (size_t i = std::max(0, (int)keys.size() - 20); i < keys.size(); ++i) { - children.push_back(text(Stringify(keys[i]))); - } - return window(text(L"keys"), vbox(std::move(children))); - } - - bool OnEvent(Event event) override { - keys.push_back(event); - return true; - } - - private: - std::vector keys; -}; - int main(int argc, const char* argv[]) { auto screen = ScreenInteractive::TerminalOutput(); - screen.Loop(Make()); + + std::vector keys; + + auto component = Renderer([&] { + Elements children; + for (size_t i = std::max(0, (int)keys.size() - 20); i < keys.size(); ++i) + children.push_back(text(Stringify(keys[i]))); + return window(text(L"keys"), vbox(std::move(children))); + }); + + component = CatchEvent(component, [&](Event event) { + keys.push_back(event); + return true; + }); + + screen.Loop(component); } diff --git a/include/ftxui/component/component.hpp b/include/ftxui/component/component.hpp index e77aff2..298d7be 100644 --- a/include/ftxui/component/component.hpp +++ b/include/ftxui/component/component.hpp @@ -13,6 +13,7 @@ namespace ftxui { class ComponentBase; +struct Event; using Component = std::shared_ptr; using Components = std::vector; @@ -30,10 +31,11 @@ Component Input(StringRef content, ConstStringRef placeholder); Component Menu(const std::vector* entries, int* selected_); Component Radiobox(const std::vector* entries, int* selected_); Component Toggle(const std::vector* entries, int* selected); -Component Renderer(Component child, std::function); -Component Renderer(std::function); template // T = {int, float} Component Slider(StringRef label, T* value, T min, T max, T increment); +Component Renderer(Component child, std::function); +Component Renderer(std::function); +Component CatchEvent(Component child, std::function); namespace Container { Component Vertical(Components children); diff --git a/include/ftxui/dom/node.hpp b/include/ftxui/dom/node.hpp index e47121e..7c66375 100644 --- a/include/ftxui/dom/node.hpp +++ b/include/ftxui/dom/node.hpp @@ -35,7 +35,6 @@ class Node { // Step 3: Draw this element. virtual void Render(Screen& screen); - protected: std::vector children_; Requirement requirement_; diff --git a/src/ftxui/component/catch_event.cpp b/src/ftxui/component/catch_event.cpp new file mode 100644 index 0000000..a1c9479 --- /dev/null +++ b/src/ftxui/component/catch_event.cpp @@ -0,0 +1,57 @@ +#include // for function +#include // for __shared_ptr_access, __shared_ptr_access<>::element_type, shared_ptr +#include // for move + +#include "ftxui/component/component.hpp" // for Component, Make, CatchEvent +#include "ftxui/component/component_base.hpp" // for ComponentBase +#include "ftxui/component/event.hpp" // for Event + +namespace ftxui { + +/// @brief A component executing a provided function for catching events. +/// @ingroup component. +class CatchEventBase : public ComponentBase { + public: + // Constructor. + CatchEventBase(std::function on_event) + : on_event_(std::move(on_event)) {} + ~CatchEventBase() override = default; + + // Component implementation. + bool OnEvent(Event event) override { + if (on_event_(event)) + return true; + else + return ComponentBase::OnEvent(event); + } + + protected: + std::function on_event_; +}; + +/// @brief Return a component, using |on_event| to catch events. This function +/// must returns true when the event has been handled, false otherwise. +/// @param on_event The function drawing the interface. +/// @ingroup component +/// +/// ### Example +/// +/// ```cpp +/// auto screen = ScreenInteractive::TerminalOutput(); +/// auto renderer = Renderer([] { +/// return text(L"My interface"); +/// }); +/// screen.Loop(renderer); +/// ``` +Component CatchEvent(Component child, + std::function on_event) { + auto out = Make(std::move(on_event)); + out->Add(std::move(child)); + return out; +} + +} // namespace ftxui + +// Copyright 2021 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. diff --git a/src/ftxui/screen/string.cpp b/src/ftxui/screen/string.cpp index 6b0ea92..1323265 100644 --- a/src/ftxui/screen/string.cpp +++ b/src/ftxui/screen/string.cpp @@ -1,7 +1,8 @@ #include "ftxui/screen/string.hpp" -#include -#include +#include // for codecvt_utf8_utf16 +#include // for wstring_convert +#include // for move namespace ftxui { #ifdef _MSC_VER