diff --git a/.github/workflows/linux-clang.yaml b/.github/workflows/linux-clang.yaml index 2b3a09812aff3773dc89f6f04b99284b09b4560d..d86d0d3eea3c5995752b3d8e5477e805c146023c 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 c5cbc4f9afd56c4d2058b44d221659ebdc283663..ffa8ca128186d3143c32645d9fa5c58c3f5c6679 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 5bc7852170b9c455eec9dfc644d8e77c13c786a0..c632caa2c2fa02e64d4a85ef98179a41d2e015eb 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 02a13b37fa38f9e30213cdf76927a308e1308b35..bd825b50f2f36698a37bbb90a58825941c9cfb26 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 <stddef.h> // for size_t -#include <algorithm> // for max -#include <ftxui/component/component.hpp> // for Make -#include <ftxui/component/screen_interactive.hpp> // for ScreenInteractive -#include <string> // for allocator, operator+, wstring, char_traits, to_wstring, string +#include <stddef.h> // for size_t +#include <algorithm> // for max +#include <memory> // for shared_ptr +#include <string> // for allocator, char_traits, operator+, wstring, basic_string, 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/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; +int main(int argc, const char* argv[]) { + auto screen = ScreenInteractive::TerminalOutput(); + + std::vector<Event> keys; - Element Render() override { + auto component = Renderer([&] { Elements children; - for (size_t i = std::max(0, (int)keys.size() - 20); i < keys.size(); ++i) { + 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 { + component = CatchEvent(component, [&](Event event) { keys.push_back(event); return true; - } - - private: - std::vector<Event> keys; -}; + }); -int main(int argc, const char* argv[]) { - auto screen = ScreenInteractive::TerminalOutput(); - screen.Loop(Make<DrawKey>()); + screen.Loop(component); } diff --git a/include/ftxui/component/component.hpp b/include/ftxui/component/component.hpp index e77aff26e2f11fd1683aff0bb25bdbe49841b5ac..298d7be357e03abce2c80b75fa016d816d199ac3 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<ComponentBase>; using Components = std::vector<Component>; @@ -30,10 +31,11 @@ Component Input(StringRef content, ConstStringRef placeholder); Component Menu(const std::vector<std::wstring>* entries, int* selected_); Component Radiobox(const std::vector<std::wstring>* entries, int* selected_); Component Toggle(const std::vector<std::wstring>* entries, int* selected); -Component Renderer(Component child, std::function<Element()>); -Component Renderer(std::function<Element()>); template <class T> // T = {int, float} Component Slider(StringRef label, T* value, T min, T max, T increment); +Component Renderer(Component child, std::function<Element()>); +Component Renderer(std::function<Element()>); +Component CatchEvent(Component child, std::function<bool(Event)>); namespace Container { Component Vertical(Components children); diff --git a/include/ftxui/dom/node.hpp b/include/ftxui/dom/node.hpp index e47121e2fc7fbe4759bf856c3e0ca4e28b073ec5..7c66375ccc05570b8a445d8e80619b14267e8818 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<Element> children_; Requirement requirement_; diff --git a/src/ftxui/component/catch_event.cpp b/src/ftxui/component/catch_event.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a1c94795f92f1c6fbd9bfab76c86f5285a3b99d7 --- /dev/null +++ b/src/ftxui/component/catch_event.cpp @@ -0,0 +1,57 @@ +#include <functional> // for function +#include <memory> // for __shared_ptr_access, __shared_ptr_access<>::element_type, shared_ptr +#include <utility> // 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<bool(Event)> 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<bool(Event)> 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<bool(Event event)> on_event) { + auto out = Make<CatchEventBase>(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 6b0ea92af7481f2a03ed96919bec6fb2d5c93338..1323265881b16cdd649f5cd9178b9abc50bb0c84 100644 --- a/src/ftxui/screen/string.cpp +++ b/src/ftxui/screen/string.cpp @@ -1,7 +1,8 @@ #include "ftxui/screen/string.hpp" -#include <codecvt> -#include <locale> +#include <codecvt> // for codecvt_utf8_utf16 +#include <locale> // for wstring_convert +#include <utility> // for move namespace ftxui { #ifdef _MSC_VER