diff --git a/examples/component/CMakeLists.txt b/examples/component/CMakeLists.txt index 29f61ab..d819a89 100644 --- a/examples/component/CMakeLists.txt +++ b/examples/component/CMakeLists.txt @@ -12,12 +12,13 @@ example(menu2) example(menu_multiple) example(menu_style) example(modal_dialog) +example(print_key_press) example(radiobox) example(radiobox_in_frame) +example(renderer) +example(resizable_split) example(slider) example(slider_rgb) example(tab_horizontal) example(tab_vertical) example(toggle) -example(resizable_split) -example(print_key_press) diff --git a/examples/component/input.cpp b/examples/component/input.cpp index 4184a01..5d8e03c 100644 --- a/examples/component/input.cpp +++ b/examples/component/input.cpp @@ -1,11 +1,12 @@ #include // for allocator, __shared_ptr_access -#include // for operator+, char_traits, wstring +#include // for char_traits, operator+, wstring, basic_string #include "ftxui/component/captured_mouse.hpp" // for ftxui #include "ftxui/component/component.hpp" // for Input, Renderer, Vertical #include "ftxui/component/component_base.hpp" // for ComponentBase +#include "ftxui/component/component_options.hpp" // for InputOption #include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive -#include "ftxui/dom/elements.hpp" // for text, hbox, Element, separator, operator|, vbox, border +#include "ftxui/dom/elements.hpp" // for text, hbox, separator, Element, operator|, vbox, border int main(int argc, const char* argv[]) { using namespace ftxui; @@ -14,7 +15,6 @@ int main(int argc, const char* argv[]) { std::wstring last_name; std::wstring password; - Component input_first_name = Input(&first_name, "first name"); Component input_last_name = Input(&last_name, "last name"); diff --git a/examples/component/renderer.cpp b/examples/component/renderer.cpp new file mode 100644 index 0000000..b80ea62 --- /dev/null +++ b/examples/component/renderer.cpp @@ -0,0 +1,49 @@ +#include // for shared_ptr, allocator, __shared_ptr_access + +#include "ftxui/component/captured_mouse.hpp" // for ftxui +#include "ftxui/component/component.hpp" // for Renderer, Button, Vertical +#include "ftxui/component/component_base.hpp" // for ComponentBase +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include "ftxui/dom/elements.hpp" // for operator|, Element, text, bold, border, center, color +#include "ftxui/screen/color.hpp" // for Color, Color::Red + +int main(int argc, const char* argv[]) { + using namespace ftxui; + auto screen = ScreenInteractive::FitComponent(); + + // A Renderer() is a component using a lambda function as a parameter to + // render itself. + + // 1. Example of focusable renderer: + auto renderer_focusable = Renderer([](bool focused) { + if (focused) + return text(L"FOCUSABLE RENDERER()") | center | bold | border; + else + return text(L" Focusable renderer() ") | center | border; + }); + + // 2. Examples of a non focusable renderer. + auto renderer_non_focusable = Renderer([&] { + return text(L"~~~~~ Non Focusable renderer() ~~~~~"); // + }); + + // 3. Renderer can wrap other components to redefine their Render() function. + auto button = Button(L"Wrapped quit button", screen.ExitLoopClosure()); + auto renderer_wrap = Renderer(button, [&] { + if (button->Focused()) + return button->Render() | bold | color(Color::Red); + else + return button->Render(); + }); + + // Let's renderer everyone: + screen.Loop(Container::Vertical({ + renderer_focusable, + renderer_non_focusable, + renderer_wrap, + })); +} + +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. diff --git a/include/ftxui/component/component.hpp b/include/ftxui/component/component.hpp index 1bedac6..3b7f3ff 100644 --- a/include/ftxui/component/component.hpp +++ b/include/ftxui/component/component.hpp @@ -51,6 +51,7 @@ Component ResizableSplitTop(Component main, Component back, int* main_size); Component ResizableSplitBottom(Component main, Component back, int* main_size); Component Renderer(Component child, std::function); Component Renderer(std::function); +Component Renderer(std::function); Component CatchEvent(Component child, std::function); namespace Container { diff --git a/include/ftxui/screen/screen.hpp b/include/ftxui/screen/screen.hpp index ba45bc3..37f2096 100644 --- a/include/ftxui/screen/screen.hpp +++ b/include/ftxui/screen/screen.hpp @@ -2,12 +2,12 @@ #define FTXUI_SCREEN_SCREEN #include -#include -#include +#include // for allocator, wstring, string, basic_string +#include // for vector -#include "ftxui/screen/box.hpp" -#include "ftxui/screen/color.hpp" -#include "ftxui/screen/terminal.hpp" +#include "ftxui/screen/box.hpp" // for Box +#include "ftxui/screen/color.hpp" // for Color, Color::Default +#include "ftxui/screen/terminal.hpp" // for Dimensions namespace ftxui { diff --git a/src/ftxui/component/button.cpp b/src/ftxui/component/button.cpp index 889bcad..b540e2d 100644 --- a/src/ftxui/component/button.cpp +++ b/src/ftxui/component/button.cpp @@ -53,9 +53,7 @@ class ButtonBase : public ComponentBase { return false; } - bool Focusable() const final { - return true; - } + bool Focusable() const final { return true; } private: ConstStringRef label_; diff --git a/src/ftxui/component/checkbox.cpp b/src/ftxui/component/checkbox.cpp index de46ccc..70e5d2e 100644 --- a/src/ftxui/component/checkbox.cpp +++ b/src/ftxui/component/checkbox.cpp @@ -71,9 +71,7 @@ class CheckboxBase : public ComponentBase { return false; } - bool Focusable() const final { - return true; - } + bool Focusable() const final { return true; } ConstStringRef label_; bool* const state_; diff --git a/src/ftxui/component/input.cpp b/src/ftxui/component/input.cpp index 061a106..7eded8b 100644 --- a/src/ftxui/component/input.cpp +++ b/src/ftxui/component/input.cpp @@ -56,10 +56,9 @@ class InputBase : public ComponentBase { 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) - : L""; + std::wstring part_after_cursor = cursor_position() < (int)content.size() - 1 + ? content.substr(cursor_position() + 1) + : L""; auto focused = is_focused ? focus : select; // clang-format off @@ -164,9 +163,7 @@ class InputBase : public ComponentBase { return true; } - bool Focusable() const final { - return true; - } + bool Focusable() const final { return true; } StringRef content_; ConstStringRef placeholder_; diff --git a/src/ftxui/component/input_test.cpp b/src/ftxui/component/input_test.cpp index 1e61bcc..94a26e2 100644 --- a/src/ftxui/component/input_test.cpp +++ b/src/ftxui/component/input_test.cpp @@ -3,11 +3,14 @@ #include // for __shared_ptr_access, shared_ptr, allocator #include // for wstring -#include "ftxui/component/captured_mouse.hpp" // for ftxui -#include "ftxui/component/component.hpp" // for Input, Component -#include "ftxui/component/component_base.hpp" // for ComponentBase +#include "ftxui/component/captured_mouse.hpp" // for ftxui +#include "ftxui/component/component.hpp" // for Input +#include "ftxui/component/component_base.hpp" // for ComponentBase, Component #include "ftxui/component/component_options.hpp" // for InputOption #include "ftxui/component/event.hpp" // for Event, Event::ArrowLeft, Event::ArrowRight, Event::Backspace, Event::Delete, Event::End, Event::Home +#include "ftxui/dom/elements.hpp" // for Fit +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/screen.hpp" // for Screen, Pixel #include "ftxui/util/ref.hpp" // for Ref #include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST diff --git a/src/ftxui/component/menu.cpp b/src/ftxui/component/menu.cpp index 8c97bee..3342b22 100644 --- a/src/ftxui/component/menu.cpp +++ b/src/ftxui/component/menu.cpp @@ -106,9 +106,7 @@ class MenuBase : public ComponentBase { return false; } - bool Focusable() const final { - return entries_->size(); - } + bool Focusable() const final { return entries_->size(); } int& focused_entry() { return option_->focused_entry(); } diff --git a/src/ftxui/component/radiobox.cpp b/src/ftxui/component/radiobox.cpp index d61fe30..5666ba3 100644 --- a/src/ftxui/component/radiobox.cpp +++ b/src/ftxui/component/radiobox.cpp @@ -119,9 +119,7 @@ class RadioboxBase : public ComponentBase { return false; } - bool Focusable() const final { - return entries_->size(); - } + bool Focusable() const final { return entries_->size(); } int& focused_entry() { return option_->focused_entry(); } diff --git a/src/ftxui/component/renderer.cpp b/src/ftxui/component/renderer.cpp index 9e51630..923a28f 100644 --- a/src/ftxui/component/renderer.cpp +++ b/src/ftxui/component/renderer.cpp @@ -1,31 +1,17 @@ #include // for function -#include // for __shared_ptr_access +#include // for __shared_ptr_access, shared_ptr #include // for move -#include "ftxui/component/component.hpp" // for Component, Make, Renderer -#include "ftxui/component/component_base.hpp" // for ComponentBase -#include "ftxui/dom/elements.hpp" // for Element +#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse +#include "ftxui/component/component.hpp" // for Make, Renderer +#include "ftxui/component/component_base.hpp" // for Component, ComponentBase +#include "ftxui/component/event.hpp" // for Event +#include "ftxui/component/mouse.hpp" // for Mouse +#include "ftxui/dom/elements.hpp" // for Element, operator|, reflect +#include "ftxui/screen/box.hpp" // for Box namespace ftxui { -// @brief A component rendering Element from a function. -class RendererBase : public ComponentBase { - public: - // Access this interface from a Component - static RendererBase* From(Component component) { - return static_cast(component.get()); - } - - // Constructor. - RendererBase(std::function render) : render_(std::move(render)) {} - - // Component implementation. - Element Render() override { return render_(); } - - protected: - std::function render_; -}; - /// @brief Return a component, using |render| to render its interface. /// @param render The function drawing the interface. /// @ingroup component @@ -40,7 +26,14 @@ class RendererBase : public ComponentBase { /// screen.Loop(renderer); /// ``` Component Renderer(std::function render) { - return Make(std::move(render)); + class Impl : public ComponentBase { + public: + Impl(std::function render) : render_(std::move(render)) {} + Element Render() override { return render_(); } + std::function render_; + }; + + return Make(std::move(render)); } /// @brief Return a new Component, similar to |child|, but using |render| as the @@ -69,6 +62,48 @@ Component Renderer(Component child, std::function render) { return renderer; } +/// @brief Return a focusable component, using |render| to render its interface. +/// @param render The function drawing the interface, taking a boolean telling +/// whether the component is focused or not. +/// @ingroup component +/// +/// ### Example +/// +/// ```cpp +/// auto screen = ScreenInteractive::TerminalOutput(); +/// auto renderer = Renderer([] (bool focused) { +/// if (focused) +/// return text("My interface") | inverted; +/// else +/// return text("My interface") | inverted; +/// }); +/// screen.Loop(renderer); +/// ``` +Component Renderer(std::function render) { + class Impl : public ComponentBase { + public: + Impl(std::function render) : render_(std::move(render)) {} + + private: + Element Render() override { return render_(Focused()) | reflect(box_); } + bool Focusable() const override { return true; } + bool OnEvent(Event event) override { + if (event.is_mouse() && box_.Contain(event.mouse().x, event.mouse().y)) { + if (!CaptureMouse(event)) + return false; + + TakeFocus(); + } + + return false; + } + Box box_; + + std::function render_; + }; + return Make(std::move(render)); +} + } // namespace ftxui // Copyright 2021 Arthur Sonzogni. All rights reserved. diff --git a/src/ftxui/component/slider.cpp b/src/ftxui/component/slider.cpp index da5f2b7..2a4f334 100644 --- a/src/ftxui/component/slider.cpp +++ b/src/ftxui/component/slider.cpp @@ -84,9 +84,7 @@ class SliderBase : public ComponentBase { return false; } - bool Focusable() const final { - return true; - } + bool Focusable() const final { return true; } private: StringRef label_; diff --git a/src/ftxui/dom/clear_under.cpp b/src/ftxui/dom/clear_under.cpp index 12501f4..17bc1ff 100644 --- a/src/ftxui/dom/clear_under.cpp +++ b/src/ftxui/dom/clear_under.cpp @@ -1,8 +1,8 @@ #include // for make_shared #include // for move -#include "ftxui/dom/elements.hpp" // for Element, clear_under -#include "ftxui/dom/node.hpp" // for Node +#include "ftxui/dom/elements.hpp" // for Element, 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 diff --git a/src/ftxui/dom/inverted.cpp b/src/ftxui/dom/inverted.cpp index 00a67b2..bad2c1d 100644 --- a/src/ftxui/dom/inverted.cpp +++ b/src/ftxui/dom/inverted.cpp @@ -1,8 +1,8 @@ #include // for make_shared #include // for move -#include "ftxui/dom/elements.hpp" // for Element, inverted -#include "ftxui/dom/node.hpp" // for Node +#include "ftxui/dom/elements.hpp" // for Element, 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 diff --git a/src/ftxui/dom/node_decorator.hpp b/src/ftxui/dom/node_decorator.hpp index be62a2c..41d75e8 100644 --- a/src/ftxui/dom/node_decorator.hpp +++ b/src/ftxui/dom/node_decorator.hpp @@ -4,7 +4,7 @@ #include // for move #include "ftxui/dom/elements.hpp" // for Element, unpack -#include "ftxui/dom/node.hpp" // for Node +#include "ftxui/dom/node.hpp" // for Node namespace ftxui { struct Box; diff --git a/src/ftxui/dom/underlined.cpp b/src/ftxui/dom/underlined.cpp index 85df371..ce217e8 100644 --- a/src/ftxui/dom/underlined.cpp +++ b/src/ftxui/dom/underlined.cpp @@ -1,8 +1,8 @@ #include // for make_shared #include // for move -#include "ftxui/dom/elements.hpp" // for Element, underlined -#include "ftxui/dom/node.hpp" // for Node +#include "ftxui/dom/elements.hpp" // for Element, 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 diff --git a/src/ftxui/dom/util.cpp b/src/ftxui/dom/util.cpp index ba08a7b..23a2c61 100644 --- a/src/ftxui/dom/util.cpp +++ b/src/ftxui/dom/util.cpp @@ -1,8 +1,14 @@ +#include // for min #include // for function +#include // for __shared_ptr_access #include // for move #include // for vector -#include "ftxui/dom/elements.hpp" // for Decorator, Element, Elements, operator|, nothing +#include "ftxui/dom/elements.hpp" // for Element, Decorator, Elements, operator|, Fit, nothing +#include "ftxui/dom/node.hpp" // for Node +#include "ftxui/dom/requirement.hpp" // for Requirement +#include "ftxui/screen/screen.hpp" // for Full +#include "ftxui/screen/terminal.hpp" // for Dimensions namespace ftxui { diff --git a/src/ftxui/screen/screen.cpp b/src/ftxui/screen/screen.cpp index 1200d56..3a9ef50 100644 --- a/src/ftxui/screen/screen.cpp +++ b/src/ftxui/screen/screen.cpp @@ -1,10 +1,11 @@ -#include // for min +#include // for max #include // for operator<<, basic_ostream, wstringstream, stringstream, flush, cout, ostream +#include // for allocator #include // IWYU pragma: keep #include "ftxui/screen/screen.hpp" #include "ftxui/screen/string.hpp" // for to_string, wchar_width -#include "ftxui/screen/terminal.hpp" // for Terminal::Dimensions, Terminal +#include "ftxui/screen/terminal.hpp" // for Dimensions, Size #if defined(_WIN32) #define WIN32_LEAN_AND_MEAN