From 4da63b926042247151726184ea4481618c763093 Mon Sep 17 00:00:00 2001 From: Arthur Sonzogni Date: Sun, 13 Mar 2022 18:51:46 +0100 Subject: [PATCH] Animation (#355) --- CHANGELOG.md | 51 +- CMakeLists.txt | 5 +- cmake/ftxui_test.cmake | 2 - examples/CMakeLists.txt | 3 + examples/component/CMakeLists.txt | 4 + examples/component/button.cpp | 13 +- examples/component/button_animated.cpp | 46 ++ examples/component/button_style.cpp | 62 +++ examples/component/canvas_animated.cpp | 16 +- examples/component/checkbox_in_frame.cpp | 13 +- examples/component/composition.cpp | 16 +- examples/component/homescreen.cpp | 264 ++++++----- examples/component/menu_entries.cpp | 24 +- examples/component/menu_entries_animated.cpp | 66 +++ examples/component/menu_style.cpp | 310 +++++++++--- .../menu_underline_animated_gallery.cpp | 94 ++++ examples/dom/color_gallery.cpp | 5 +- examples/dom/color_info_sorted_2d.ipp | 17 +- examples/index.html | 9 +- include/ftxui/component/animation.hpp | 119 +++++ include/ftxui/component/component.hpp | 15 +- include/ftxui/component/component_base.hpp | 7 + include/ftxui/component/component_options.hpp | 167 ++++--- .../ftxui/component/screen_interactive.hpp | 9 + include/ftxui/component/task.hpp | 8 +- include/ftxui/dom/elements.hpp | 8 + include/ftxui/screen/color.hpp | 1 + src/ftxui/component/animation.cpp | 285 +++++++++++ src/ftxui/component/button.cpp | 188 +++++--- src/ftxui/component/checkbox.cpp | 30 +- src/ftxui/component/collapsible.cpp | 11 +- src/ftxui/component/component.cpp | 13 + src/ftxui/component/component_options.cpp | 228 +++++++++ src/ftxui/component/dropdown.cpp | 11 +- src/ftxui/component/input.cpp | 2 +- src/ftxui/component/menu.cpp | 441 ++++++++++++++++-- src/ftxui/component/radiobox.cpp | 28 +- src/ftxui/component/screen_interactive.cpp | 126 +++-- src/ftxui/component/toggle.cpp | 144 ------ src/ftxui/component/toggle_test.cpp | 12 +- src/ftxui/component/util.cpp | 6 +- src/ftxui/dom/separator.cpp | 143 +++++- src/ftxui/screen/color.cpp | 71 +++ 43 files changed, 2439 insertions(+), 654 deletions(-) create mode 100644 examples/component/button_animated.cpp create mode 100644 examples/component/button_style.cpp create mode 100644 examples/component/menu_entries_animated.cpp create mode 100644 examples/component/menu_underline_animated_gallery.cpp create mode 100644 include/ftxui/component/animation.hpp create mode 100644 src/ftxui/component/animation.cpp create mode 100644 src/ftxui/component/component_options.cpp delete mode 100644 src/ftxui/component/toggle.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ac5a71..1a18c33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,33 @@ current (development) - **breaking**: The library prefix is now back to "lib" (the default). This means non-cmake users should not link against "libftxui-dom" for instance. +### Component +- Animations module! Components can implement the `OnAnimation` method and the + animation::Animator to define some animated properties. + - `Menu` now support animations. + - `Button` now supports animations. +- Support SIGTSTP. (ctrl+z). +- Support task posting. `ScreenInteractive::Post(Task)`. +- `Menu` can now be used in the 4 directions, using `MenuOption.direction`. +- `Menu` can display an animated underline, using + `MenuOption.underline.enabled`. +- **breaking** All the options are now using a transform function. +- **breaking** The `Toggle` component is now implemented using `Menu`. +- **bugfix** Container::Tab implements `Focusable()`. +- **bugfix** Improved default implementations of ComponentBase `Focusable()` and + `ActiveChild()` methods. +- **bugfix** Automatically convert '\r' keys into '\n' for Linux programs that + do not send the correct code for the return key, like the 'bind'. + https://github.com/ArthurSonzogni/FTXUI/issues/337 +- Add decorator for components: + - `operator|(Component, ComponentDecorator)` + - `operator|(Component, ElementDecorator)` + - `operator|=(Component, ComponentDecorator)` + - `operator|=(Component, ElementDecorator)` + - Add the `Maybe` decorator. + - Add the `CatchEvent` decorator. + - Add the `Renderer` decorator. + ### DOM: - **breaking**: The `inverted` decorator now toggle in the inverted attribute. - Add `gauge` for the 4 directions. Expose the following API: @@ -19,29 +46,17 @@ Element gaugeUp(float ratio); Element gaugeDown(float ratio); Element gaugeDirection(float ratio, GaugeDirection); ``` +- Add `separatorHSelector` and `separatorVSelector` elements. This can be used + to highlight an area. - Add the `automerge` decorator. This makes separator characters to be merged with others nearby. - Fix the `Table` rendering function, to allow automerging characters. -- Bugfix: The `vscroll_indicator` now computes its offset and size correctly. +- **Bugfix**: The `vscroll_indicator` now computes its offset and size + correctly. - Add the `operator|=(Element, Decorator)` -### Component -- Support SIGTSTP. (ctrl+z). -- Support task posting. `ScreenInteractive::Post(Task)`. -- **bugfix** Container::Tab implements `Focusable()`. -- **bugfix** Improved default implementations of ComponentBase `Focusable()` and - `ActiveChild()` methods. -- **bugfix** Automatically convert '\r' keys into '\n' for Linux programs that - do not send the correct code for the return key, like the 'bind'. - https://github.com/ArthurSonzogni/FTXUI/issues/337 -- Add decorator for components: - - `operator|(Component, ComponentDecorator)` - - `operator|=(Component, ComponentDecorator)` - - `operator|(Component, ElementDecorator)` - - `operator|=(Component, ElementDecorator)` - - Add the `Maybe` decorator. - - Add the `CatchEvent` decorator. - - Add the `Renderer` decorator. +### Screen: +- Add: `Color::Interpolate(lambda, color_a, color_b)`. 2.0.0 ----- diff --git a/CMakeLists.txt b/CMakeLists.txt index 930ff87..b4c784f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,19 +84,23 @@ add_library(dom ) add_library(component + include/ftxui/component/animation.hpp include/ftxui/component/captured_mouse.hpp include/ftxui/component/component.hpp include/ftxui/component/component_base.hpp + include/ftxui/component/component_options.hpp include/ftxui/component/event.hpp include/ftxui/component/mouse.hpp include/ftxui/component/receiver.hpp include/ftxui/component/screen_interactive.hpp include/ftxui/component/task.hpp + src/ftxui/component/animation.cpp src/ftxui/component/button.cpp src/ftxui/component/catch_event.cpp src/ftxui/component/checkbox.cpp src/ftxui/component/collapsible.cpp src/ftxui/component/component.cpp + src/ftxui/component/component_options.cpp src/ftxui/component/container.cpp src/ftxui/component/dropdown.cpp src/ftxui/component/event.cpp @@ -111,7 +115,6 @@ add_library(component src/ftxui/component/slider.cpp src/ftxui/component/terminal_input_parser.cpp src/ftxui/component/terminal_input_parser.hpp - src/ftxui/component/toggle.cpp src/ftxui/component/util.cpp ) diff --git a/cmake/ftxui_test.cmake b/cmake/ftxui_test.cmake index e4f83d5..f438866 100644 --- a/cmake/ftxui_test.cmake +++ b/cmake/ftxui_test.cmake @@ -44,8 +44,6 @@ target_link_libraries(tests target_include_directories(tests PRIVATE src ) -target_compile_options(tests PRIVATE -fsanitize=address) -target_link_libraries(tests PRIVATE -fsanitize=address) if (NOT MSVC) include(cmake/ftxui_benchmark.cmake) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f5a46b0..92a6162 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -10,6 +10,9 @@ add_subdirectory(component) add_subdirectory(dom) if (EMSCRIPTEN) + # 32MB should be enough to run all the examples, in debug mode. + target_link_options(component PUBLIC "SHELL: -s TOTAL_MEMORY=33554432") + get_property(EXAMPLES GLOBAL PROPERTY FTXUI::EXAMPLES) foreach(file "index.html" diff --git a/examples/component/CMakeLists.txt b/examples/component/CMakeLists.txt index 6267d72..4c135df 100644 --- a/examples/component/CMakeLists.txt +++ b/examples/component/CMakeLists.txt @@ -1,6 +1,8 @@ set(DIRECTORY_LIB component) example(button) +example(button_animated) +example(button_style) example(canvas_animated) example(checkbox) example(checkbox_in_frame) @@ -16,9 +18,11 @@ example(maybe) example(menu) example(menu2) example(menu_entries) +example(menu_entries_animated) example(menu_in_frame) example(menu_multiple) example(menu_style) +example(menu_underline_animated_gallery) example(modal_dialog) example(nested_screen) example(print_key_press) diff --git a/examples/component/button.cpp b/examples/component/button.cpp index da645f1..b34dfb7 100644 --- a/examples/component/button.cpp +++ b/examples/component/button.cpp @@ -1,12 +1,11 @@ #include // for shared_ptr, __shared_ptr_access -#include // for operator+, to_wstring +#include // for operator+, to_string #include "ftxui/component/captured_mouse.hpp" // for ftxui #include "ftxui/component/component.hpp" // for Button, Horizontal, Renderer #include "ftxui/component/component_base.hpp" // for ComponentBase -#include "ftxui/component/component_options.hpp" // for ButtonOption #include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive -#include "ftxui/dom/elements.hpp" // for separator, gauge, Element, operator|, vbox, border +#include "ftxui/dom/elements.hpp" // for separator, gauge, text, Element, operator|, vbox, border using namespace ftxui; @@ -14,13 +13,9 @@ int main(int argc, const char* argv[]) { int value = 50; // The tree of components. This defines how to navigate using the keyboard. - auto button_option = ButtonOption(); - button_option.border = false; auto buttons = Container::Horizontal({ - Button( - "[Decrease]", [&] { value--; }, &button_option), - Button( - "[Increase]", [&] { value++; }, &button_option), + Button("Decrease", [&] { value--; }), + Button("Increase", [&] { value++; }), }); // Modify the way to render them on screen: diff --git a/examples/component/button_animated.cpp b/examples/component/button_animated.cpp new file mode 100644 index 0000000..9d7948a --- /dev/null +++ b/examples/component/button_animated.cpp @@ -0,0 +1,46 @@ +#include // for shared_ptr, __shared_ptr_access +#include // for operator+, to_string + +#include "ftxui/component/captured_mouse.hpp" // for ftxui +#include "ftxui/component/component.hpp" // for Button, Horizontal, Renderer +#include "ftxui/component/component_base.hpp" // for ComponentBase +#include "ftxui/component/component_options.hpp" // for ButtonOption +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include "ftxui/dom/elements.hpp" // for gauge, separator, text, vbox, operator|, Element, border +#include "ftxui/screen/color.hpp" // for Color, Color::Blue, Color::Green, Color::Red + +using namespace ftxui; + +int main(int argc, const char* argv[]) { + int value = 50; + + // The tree of components. This defines how to navigate using the keyboard. + auto buttons = Container::Horizontal({ + Button( + "Decrease", [&] { value--; }, ButtonOption::Animated(Color::Red)), + Button( + "Reset", [&] { value = 50; }, ButtonOption::Animated(Color::Green)), + Button( + "Increase", [&] { value++; }, ButtonOption::Animated(Color::Blue)), + }); + + // Modify the way to render them on screen: + auto component = Renderer(buttons, [&] { + return vbox({ + vbox({ + text("value = " + std::to_string(value)), + separator(), + gauge(value * 0.01f), + }) | border, + buttons->Render(), + }); + }); + + auto screen = ScreenInteractive::FitComponent(); + screen.Loop(component); + return 0; +} + +// 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/examples/component/button_style.cpp b/examples/component/button_style.cpp new file mode 100644 index 0000000..7473263 --- /dev/null +++ b/examples/component/button_style.cpp @@ -0,0 +1,62 @@ +#include // for shared_ptr, __shared_ptr_access +#include // for operator+, to_string + +#include "ftxui/component/captured_mouse.hpp" // for ftxui +#include "ftxui/component/component.hpp" // for Button, Horizontal, Renderer +#include "ftxui/component/component_base.hpp" // for ComponentBase +#include "ftxui/component/component_options.hpp" // for ButtonOption +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include "ftxui/dom/elements.hpp" // for gauge, separator, text, vbox, operator|, Element, border +#include "ftxui/screen/color.hpp" // for Color, Color::Blue, Color::Green, Color::Red + +using namespace ftxui; + +int main(int argc, const char* argv[]) { + int value = 0; + auto action = [&] { value++; }; + auto action_renderer = + Renderer([&] { return text("count = " + std::to_string(value)); }); + + auto buttons = + Container::Vertical({ + action_renderer, + Renderer([] { return separator(); }), + Container::Horizontal({ + Container::Vertical({ + Button("Ascii 1", action, ButtonOption::Ascii()), + Button("Ascii 2", action, ButtonOption::Ascii()), + Button("Ascii 3", action, ButtonOption::Ascii()), + }), + Renderer([] { return separator(); }), + Container::Vertical({ + Button("Simple 1", action, ButtonOption::Simple()), + Button("Simple 2", action, ButtonOption::Simple()), + Button("Simple 3", action, ButtonOption::Simple()), + }), + Renderer([] { return separator(); }), + Container::Vertical({ + Button("Animated 1", action, ButtonOption::Animated()), + Button("Animated 2", action, ButtonOption::Animated()), + Button("Animated 3", action, ButtonOption::Animated()), + }), + Renderer([] { return separator(); }), + Container::Vertical({ + Button("Animated 4", action, + ButtonOption::Animated(Color::Red)), + Button("Animated 5", action, + ButtonOption::Animated(Color::Green)), + Button("Animated 6", action, + ButtonOption::Animated(Color::Blue)), + }), + }), + }) | + border; + + auto screen = ScreenInteractive::FitComponent(); + screen.Loop(buttons); + return 0; +} + +// 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/examples/component/canvas_animated.cpp b/examples/component/canvas_animated.cpp index f428c1d..19fc33d 100644 --- a/examples/component/canvas_animated.cpp +++ b/examples/component/canvas_animated.cpp @@ -126,9 +126,9 @@ int main(int argc, const char* argv[]) { std::vector ys(100); for (int x = 0; x < 100; x++) { - float dx = x - mouse_x; - float dy = 50; - ys[x] = dy + 20 * cos(dx * 0.14) + 10 * sin(dx * 0.42); + float dx = float(x - mouse_x); + float dy = 50.f; + ys[x] = int(dy + 20 * cos(dx * 0.14) + 10 * sin(dx * 0.42)); } for (int x = 1; x < 99; x++) c.DrawPointLine(x, ys[x], x + 1, ys[x + 1]); @@ -141,10 +141,10 @@ int main(int argc, const char* argv[]) { c.DrawText(0, 0, "A symmetrical graph filled"); std::vector ys(100); for (int x = 0; x < 100; x++) { - ys[x] = 30 + // - 10 * cos(x * 0.2 - mouse_x * 0.05) + // - 5 * sin(x * 0.4) + // - 5 * sin(x * 0.3 - mouse_y * 0.05); // + ys[x] = int(30 + // + 10 * cos(x * 0.2 - mouse_x * 0.05) + // + 5 * sin(x * 0.4) + // + 5 * sin(x * 0.3 - mouse_y * 0.05)); // } for (int x = 0; x < 100; x++) { c.DrawPointLine(x, 50 + ys[x], x, 50 - ys[x], Color::Red); @@ -167,7 +167,7 @@ int main(int argc, const char* argv[]) { for (int x = 0; x < size; x++) { float dx = x - mx; float dy = y - my; - ys[y][x] = -1.5 + 3.0 * std::exp(-0.2f * (dx * dx + dy * dy)); + ys[y][x] = (int)(-1.5 + 3.0 * std::exp(-0.2f * (dx * dx + dy * dy))); } } for (int y = 0; y < size; y++) { diff --git a/examples/component/checkbox_in_frame.cpp b/examples/component/checkbox_in_frame.cpp index 512e0dd..92bf4e6 100644 --- a/examples/component/checkbox_in_frame.cpp +++ b/examples/component/checkbox_in_frame.cpp @@ -1,3 +1,4 @@ +#include // for array #include // for shared_ptr, __shared_ptr_access, allocator_traits<>::value_type #include // for operator+, to_string #include // for vector @@ -10,17 +11,13 @@ using namespace ftxui; -struct CheckboxState { - bool checked; -}; - int main(int argc, const char* argv[]) { - std::vector states(30); + std::array states; + auto container = Container::Vertical({}); for (int i = 0; i < 30; ++i) { - states[i].checked = false; - container->Add( - Checkbox("Checkbox" + std::to_string(i), &states[i].checked)); + states[i] = false; + container->Add(Checkbox("Checkbox" + std::to_string(i), &states[i])); } auto renderer = Renderer(container, [&] { diff --git a/examples/component/composition.cpp b/examples/component/composition.cpp index 5fc56d3..9bc7470 100644 --- a/examples/component/composition.cpp +++ b/examples/component/composition.cpp @@ -4,7 +4,6 @@ #include "ftxui/component/captured_mouse.hpp" // for ftxui #include "ftxui/component/component.hpp" // for Button, Horizontal, Renderer #include "ftxui/component/component_base.hpp" // for ComponentBase -#include "ftxui/component/component_options.hpp" // for ButtonOption #include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive #include "ftxui/dom/elements.hpp" // for text, separator, Element, operator|, vbox, border @@ -13,24 +12,17 @@ using namespace ftxui; // An example of how to compose multiple components into one and maintain their // interactiveness. int main(int argc, const char* argv[]) { - auto button_option = ButtonOption(); - button_option.border = false; - auto left_count = 0; auto right_count = 0; auto left_buttons = Container::Horizontal({ - Button( - "[Decrease]", [&] { left_count--; }, &button_option), - Button( - "[Increase]", [&] { left_count++; }, &button_option), + Button("Decrease", [&] { left_count--; }), + Button("Increase", [&] { left_count++; }), }); auto right_buttons = Container::Horizontal({ - Button( - "[Decrease]", [&] { right_count--; }, &button_option), - Button( - "[Increase]", [&] { right_count++; }, &button_option), + Button("Decrease", [&] { right_count--; }), + Button("Increase", [&] { right_count++; }), }); // Renderer decorates its child with a new rendering function. The way the diff --git a/examples/component/homescreen.cpp b/examples/component/homescreen.cpp index 0fbdd2b..d8af183 100644 --- a/examples/component/homescreen.cpp +++ b/examples/component/homescreen.cpp @@ -9,15 +9,17 @@ #include // for move #include // for vector -#include "ftxui/component/captured_mouse.hpp" // for ftxui -#include "ftxui/component/component.hpp" // for Checkbox, Renderer, Horizontal, Vertical, Input, Menu, Radiobox, ResizableSplitLeft, Tab, Toggle +#include "../dom/color_info_sorted_2d.ipp" // for ColorInfoSorted2D +#include "ftxui/component/component.hpp" // for Checkbox, Renderer, Horizontal, Vertical, Input, Menu, Radiobox, ResizableSplitLeft, Tab #include "ftxui/component/component_base.hpp" // for ComponentBase -#include "ftxui/component/component_options.hpp" // for InputOption +#include "ftxui/component/component_options.hpp" // for MenuOption, InputOption #include "ftxui/component/event.hpp" // for Event, Event::Custom #include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive -#include "ftxui/dom/elements.hpp" // for text, operator|, color, bgcolor, filler, Element, size, vbox, flex, hbox, separator, graph, EQUAL, paragraph, hcenter, WIDTH, bold, window, border, vscroll_indicator, Elements, HEIGHT, hflow, frame, flex_grow, flexbox, gauge, paragraphAlignCenter, paragraphAlignJustify, paragraphAlignLeft, paragraphAlignRight, dim, spinner, Decorator, LESS_THAN, center, yflex, GREATER_THAN -#include "ftxui/screen/color.hpp" // for Color, Color::Blue, Color::BlueLight, Color::RedLight, Color::Black, 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 -#include "ftxui/screen/terminal.hpp" // for Size, Dimensions +#include "ftxui/dom/elements.hpp" // for text, color, operator|, bgcolor, filler, Element, vbox, size, hbox, separator, flex, window, graph, EQUAL, paragraph, WIDTH, hcenter, Elements, bold, vscroll_indicator, HEIGHT, flexbox, hflow, border, frame, flex_grow, gauge, paragraphAlignCenter, paragraphAlignJustify, paragraphAlignLeft, paragraphAlignRight, dim, spinner, LESS_THAN, center, yframe, GREATER_THAN +#include "ftxui/dom/flexbox_config.hpp" // for FlexboxConfig +#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, Color::Palette256, ftxui +#include "ftxui/screen/color_info.hpp" // for ColorInfo +#include "ftxui/screen/terminal.hpp" // for Size, Dimensions using namespace ftxui; @@ -27,7 +29,6 @@ int main(int argc, const char* argv[]) { // --------------------------------------------------------------------------- // HTOP // --------------------------------------------------------------------------- - int shift = 0; auto my_graph = [&shift](int width, int height) { @@ -95,7 +96,7 @@ int main(int argc, const char* argv[]) { separator(), ram | flex, }) | - flex | border; + flex; }); // --------------------------------------------------------------------------- @@ -255,7 +256,7 @@ int main(int argc, const char* argv[]) { }) | size(HEIGHT, LESS_THAN, 8), hflow(render_command()) | flex_grow, }) | - flex_grow | border; + flex_grow; }); // --------------------------------------------------------------------------- @@ -267,61 +268,116 @@ int main(int argc, const char* argv[]) { entries.push_back(spinner(i, shift / 2) | bold | size(WIDTH, GREATER_THAN, 2) | border); } - return hflow(std::move(entries)) | border; + return hflow(std::move(entries)); }); // --------------------------------------------------------------------------- // Colors // --------------------------------------------------------------------------- auto color_tab_renderer = Renderer([] { - return hbox({ - vbox({ - color(Color::Default, text("Default")), - color(Color::Black, text("Black")), - color(Color::GrayDark, text("GrayDark")), - color(Color::GrayLight, text("GrayLight")), - color(Color::White, text("White")), - color(Color::Blue, text("Blue")), - color(Color::BlueLight, text("BlueLight")), - color(Color::Cyan, text("Cyan")), - color(Color::CyanLight, text("CyanLight")), - color(Color::Green, text("Green")), - color(Color::GreenLight, text("GreenLight")), - color(Color::Magenta, text("Magenta")), - color(Color::MagentaLight, text("MagentaLight")), - color(Color::Red, text("Red")), - color(Color::RedLight, text("RedLight")), - color(Color::Yellow, text("Yellow")), - color(Color::YellowLight, text("YellowLight")), - }), - vbox({ - bgcolor(Color::Default, text("Default")), - bgcolor(Color::Black, text("Black")), - bgcolor(Color::GrayDark, text("GrayDark")), - bgcolor(Color::GrayLight, text("GrayLight")), - bgcolor(Color::White, text("White")), - bgcolor(Color::Blue, text("Blue")), - bgcolor(Color::BlueLight, text("BlueLight")), - bgcolor(Color::Cyan, text("Cyan")), - bgcolor(Color::CyanLight, text("CyanLight")), - bgcolor(Color::Green, text("Green")), - bgcolor(Color::GreenLight, text("GreenLight")), - bgcolor(Color::Magenta, text("Magenta")), - bgcolor(Color::MagentaLight, text("MagentaLight")), - bgcolor(Color::Red, text("Red")), - bgcolor(Color::RedLight, text("RedLight")), - bgcolor(Color::Yellow, text("Yellow")), - bgcolor(Color::YellowLight, text("YellowLight")), - }), - }) | - hcenter | border; + auto basic_color_display = + vbox({ + text("16 color palette:"), + separator(), + hbox({ + vbox({ + color(Color::Default, text("Default")), + color(Color::Black, text("Black")), + color(Color::GrayDark, text("GrayDark")), + color(Color::GrayLight, text("GrayLight")), + color(Color::White, text("White")), + color(Color::Blue, text("Blue")), + color(Color::BlueLight, text("BlueLight")), + color(Color::Cyan, text("Cyan")), + color(Color::CyanLight, text("CyanLight")), + color(Color::Green, text("Green")), + color(Color::GreenLight, text("GreenLight")), + color(Color::Magenta, text("Magenta")), + color(Color::MagentaLight, text("MagentaLight")), + color(Color::Red, text("Red")), + color(Color::RedLight, text("RedLight")), + color(Color::Yellow, text("Yellow")), + color(Color::YellowLight, text("YellowLight")), + }), + vbox({ + bgcolor(Color::Default, text("Default")), + bgcolor(Color::Black, text("Black")), + bgcolor(Color::GrayDark, text("GrayDark")), + bgcolor(Color::GrayLight, text("GrayLight")), + bgcolor(Color::White, text("White")), + bgcolor(Color::Blue, text("Blue")), + bgcolor(Color::BlueLight, text("BlueLight")), + bgcolor(Color::Cyan, text("Cyan")), + bgcolor(Color::CyanLight, text("CyanLight")), + bgcolor(Color::Green, text("Green")), + bgcolor(Color::GreenLight, text("GreenLight")), + bgcolor(Color::Magenta, text("Magenta")), + bgcolor(Color::MagentaLight, text("MagentaLight")), + bgcolor(Color::Red, text("Red")), + bgcolor(Color::RedLight, text("RedLight")), + bgcolor(Color::Yellow, text("Yellow")), + bgcolor(Color::YellowLight, text("YellowLight")), + }), + }), + }) | + border; + + auto palette_256_color_display = text("256 colors palette:"); + { + std::vector> info_columns = ColorInfoSorted2D(); + Elements columns; + for (auto& column : info_columns) { + Elements column_elements; + for (auto& it : column) { + column_elements.push_back( + text(" ") | bgcolor(Color(Color::Palette256(it.index_256)))); + } + columns.push_back(hbox(std::move(column_elements))); + } + palette_256_color_display = vbox({ + palette_256_color_display, + separator(), + vbox(columns), + }) | + border; + } + + // True color display. + auto true_color_display = text("TrueColors: 24bits:"); + { + int saturation = 255; + Elements array; + for (int value = 0; value < 255; value += 16) { + Elements line; + for (int hue = 0; hue < 255; hue += 6) { + line.push_back(text("▀") // + | color(Color::HSV(hue, saturation, value)) // + | bgcolor(Color::HSV(hue, saturation, value + 8))); + } + array.push_back(hbox(std::move(line))); + } + true_color_display = vbox({ + true_color_display, + separator(), + vbox(std::move(array)), + }) | + border; + } + + return flexbox( + { + basic_color_display, + palette_256_color_display, + true_color_display, + }, + FlexboxConfig().SetGap(1, 1)); }); // --------------------------------------------------------------------------- // Gauges // --------------------------------------------------------------------------- auto render_gauge = [&shift](int delta) { - float progress = (shift + delta) % 1000 / 1000.f; + float progress = (shift + delta) % 500 / 500.f; return hbox({ text(std::to_string(int(progress * 100)) + "% ") | size(WIDTH, EQUAL, 5), @@ -331,25 +387,24 @@ int main(int argc, const char* argv[]) { auto gauge_component = Renderer([render_gauge] { return vbox({ - render_gauge(0) | color(Color::Black), - render_gauge(100) | color(Color::GrayDark), - render_gauge(50) | color(Color::GrayLight), - render_gauge(6894) | color(Color::White), - separator(), - render_gauge(6841) | color(Color::Blue), - render_gauge(9813) | color(Color::BlueLight), - render_gauge(98765) | color(Color::Cyan), - render_gauge(98) | color(Color::CyanLight), - render_gauge(9846) | color(Color::Green), - render_gauge(1122) | color(Color::GreenLight), - render_gauge(84) | color(Color::Magenta), - render_gauge(645) | color(Color::MagentaLight), - render_gauge(568) | color(Color::Red), - render_gauge(2222) | color(Color::RedLight), - render_gauge(220) | color(Color::Yellow), - render_gauge(348) | color(Color::YellowLight), - }) | - border; + render_gauge(0) | color(Color::Black), + render_gauge(100) | color(Color::GrayDark), + render_gauge(50) | color(Color::GrayLight), + render_gauge(6894) | color(Color::White), + separator(), + render_gauge(6841) | color(Color::Blue), + render_gauge(9813) | color(Color::BlueLight), + render_gauge(98765) | color(Color::Cyan), + render_gauge(98) | color(Color::CyanLight), + render_gauge(9846) | color(Color::Green), + render_gauge(1122) | color(Color::GreenLight), + render_gauge(84) | color(Color::Magenta), + render_gauge(645) | color(Color::MagentaLight), + render_gauge(568) | color(Color::Red), + render_gauge(2222) | color(Color::RedLight), + render_gauge(220) | color(Color::Yellow), + render_gauge(348) | color(Color::YellowLight), + }); }); // --------------------------------------------------------------------------- @@ -363,48 +418,36 @@ int main(int argc, const char* argv[]) { }; auto paragraph_renderer_left = Renderer([&] { - auto title_style = bold | bgcolor(Color::Blue) | color(Color::Black); std::string str = "Lorem Ipsum is simply dummy text of the printing and typesetting " "industry. Lorem Ipsum has been the industry's standard dummy text " "ever since the 1500s, when an unknown printer took a galley of type " "and scrambled it to make a type specimen book."; return vbox({ - // [ Left ] - text("Align left:") | title_style, - paragraphAlignLeft(str), - // [ Center ] - text("Align center:") | title_style, - paragraphAlignCenter(str), - // [ Right ] - text("Align right:") | title_style, - paragraphAlignRight(str), - // [ Justify] - text("Align justify:") | title_style, - paragraphAlignJustify(str), - // [ Side by side ] - text("Side by side:") | title_style, - hbox({ - paragraph(str), - separator() | color(Color::Blue), - paragraph(str), - }), - // [ Misc ] - text("Elements with different size:") | title_style, - flexbox({ - make_box(10, 5), - make_box(9, 4), - make_box(8, 4), - make_box(6, 3), - make_box(10, 5), - make_box(9, 4), - make_box(8, 4), - make_box(6, 3), - make_box(10, 5), - make_box(9, 4), - make_box(8, 4), - make_box(6, 3), - }), + window(text("Align left:"), paragraphAlignLeft(str)), + window(text("Align center:"), paragraphAlignCenter(str)), + window(text("Align right:"), paragraphAlignRight(str)), + window(text("Align justify:"), paragraphAlignJustify(str)), + window(text("Side by side"), hbox({ + paragraph(str), + separator(), + paragraph(str), + })), + window(text("Elements with different size:"), + flexbox({ + make_box(10, 5), + make_box(9, 4), + make_box(8, 4), + make_box(6, 3), + make_box(10, 5), + make_box(9, 4), + make_box(8, 4), + make_box(6, 3), + make_box(10, 5), + make_box(9, 4), + make_box(8, 4), + make_box(6, 3), + })), }) | vscroll_indicator | yframe | flex; }); @@ -420,7 +463,7 @@ int main(int argc, const char* argv[]) { ¶graph_renderer_split_position); auto paragraph_renderer_group_renderer = Renderer(paragraph_renderer_group, - [&] { return paragraph_renderer_group->Render() | border; }); + [&] { return paragraph_renderer_group->Render(); }); // --------------------------------------------------------------------------- // Tabs @@ -430,7 +473,8 @@ int main(int argc, const char* argv[]) { std::vector tab_entries = { "htop", "color", "spinner", "gauge", "compiler", "paragraph", }; - auto tab_selection = Toggle(&tab_entries, &tab_index); + auto tab_selection = + Menu(&tab_entries, &tab_index, MenuOption::HorizontalAnimated()); auto tab_content = Container::Tab( { htop, @@ -450,7 +494,7 @@ int main(int argc, const char* argv[]) { auto main_renderer = Renderer(main_container, [&] { return vbox({ text("FTXUI Demo") | bold | hcenter, - tab_selection->Render() | hcenter, + tab_selection->Render(), tab_content->Render() | flex, }); }); diff --git a/examples/component/menu_entries.cpp b/examples/component/menu_entries.cpp index e5e3cf2..648c8e2 100644 --- a/examples/component/menu_entries.cpp +++ b/examples/component/menu_entries.cpp @@ -1,25 +1,31 @@ +#include // for function #include // for basic_ostream::operator<<, operator<<, endl, basic_ostream, basic_ostream<>::__ostream_type, cout, ostream -#include // for shared_ptr, __shared_ptr_access -#include // for to_string, allocator +#include // for allocator, shared_ptr, __shared_ptr_access +#include // for char_traits, to_string, operator+, string, basic_string #include "ftxui/component/captured_mouse.hpp" // for ftxui #include "ftxui/component/component.hpp" // for MenuEntry, Renderer, Vertical #include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_options.hpp" // for MenuEntryOption #include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive -#include "ftxui/dom/elements.hpp" // for operator|, separator, Element, Decorator, color, text, hbox, size, bold, frame, inverted, vbox, HEIGHT, LESS_THAN, border +#include "ftxui/dom/elements.hpp" // for operator|, Element, separator, text, hbox, size, frame, color, vbox, HEIGHT, LESS_THAN, bold, border, inverted #include "ftxui/screen/color.hpp" // for Color, Color::Blue, Color::Cyan, Color::Green, Color::Red, Color::Yellow using namespace ftxui; // Define a special style for some menu entry. MenuEntryOption Colored(ftxui::Color c) { - MenuEntryOption special_style; - special_style.style_normal = Decorator(color(c)); - special_style.style_focused = Decorator(color(c)) | inverted; - special_style.style_selected = Decorator(color(c)) | bold; - special_style.style_selected_focused = Decorator(color(c)) | inverted | bold; - return special_style; + MenuEntryOption option; + option.transform = [c](EntryState state) { + state.label = (state.active? "> " : " ") + state.label; + Element e = text(state.label) | color(c); + if (state.focused) + e = e | inverted; + if (state.active) + e = e | bold; + return e; + }; + return option; } int main(int argc, const char* argv[]) { diff --git a/examples/component/menu_entries_animated.cpp b/examples/component/menu_entries_animated.cpp new file mode 100644 index 0000000..f8b43d2 --- /dev/null +++ b/examples/component/menu_entries_animated.cpp @@ -0,0 +1,66 @@ +#include // for basic_ostream::operator<<, operator<<, endl, basic_ostream, basic_ostream<>::__ostream_type, cout, ostream +#include // for shared_ptr, __shared_ptr_access +#include // for to_string, allocator + +#include "ftxui/component/captured_mouse.hpp" // for ftxui +#include "ftxui/component/component.hpp" // for MenuEntryAnimated, Renderer, Vertical +#include "ftxui/component/component_base.hpp" // for ComponentBase +#include "ftxui/component/component_options.hpp" // for MenuEntryAnimated +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include "ftxui/dom/elements.hpp" // for operator|, separator, Element, Decorator, color, text, hbox, size, bold, frame, inverted, vbox, HEIGHT, LESS_THAN, border +#include "ftxui/screen/color.hpp" // for Color, Color::Blue, Color::Cyan, Color::Green, Color::Red, Color::Yellow + +using namespace ftxui; + +// Define a special style for some menu entry. +MenuEntryOption Colored(ftxui::Color c) { + MenuEntryOption option; + option.animated_colors.foreground.enabled = true; + option.animated_colors.background.enabled = true; + option.animated_colors.background.active = c; + option.animated_colors.background.inactive = Color::Black; + option.animated_colors.foreground.active = Color::White; + option.animated_colors.foreground.inactive = c; + return option; +} + +int main(int argc, const char* argv[]) { + auto screen = ScreenInteractive::TerminalOutput(); + + int selected = 0; + auto menu = Container::Vertical( + { + MenuEntry(" 1. rear", Colored(Color::Red)), + MenuEntry(" 2. drown", Colored(Color::Yellow)), + MenuEntry(" 3. nail", Colored(Color::Green)), + MenuEntry(" 4. quit", Colored(Color::Cyan)), + MenuEntry(" 5. decorative", Colored(Color::Blue)), + MenuEntry(" 7. costume"), + MenuEntry(" 8. pick"), + MenuEntry(" 9. oral"), + MenuEntry("11. minister"), + MenuEntry("12. football"), + MenuEntry("13. welcome"), + MenuEntry("14. copper"), + MenuEntry("15. inhabitant"), + }, + &selected); + + // Display together the menu with a border + auto renderer = Renderer(menu, [&] { + return vbox({ + hbox(text("selected = "), text(std::to_string(selected))), + separator(), + menu->Render() | frame, + }) | + border | bgcolor(Color::Black); + }); + + screen.Loop(renderer); + + std::cout << "Selected element = " << selected << std::endl; +} + +// 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/examples/component/menu_style.cpp b/examples/component/menu_style.cpp index dfb4a77..b4e92cf 100644 --- a/examples/component/menu_style.cpp +++ b/examples/component/menu_style.cpp @@ -1,100 +1,258 @@ +#include // for array +#include // for milliseconds #include // for function #include // for shared_ptr, __shared_ptr_access, allocator -#include // for string, basic_string +#include // for string, char_traits, basic_string, operator+ #include // for vector -#include "ftxui/component/captured_mouse.hpp" // for ftxui -#include "ftxui/component/component.hpp" // for Menu, Horizontal, Renderer -#include "ftxui/component/component_base.hpp" // for ComponentBase -#include "ftxui/component/component_options.hpp" // for MenuOption -#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive -#include "ftxui/dom/elements.hpp" // for operator|, color, separator, Decorator, bgcolor, flex, Element, bold, hbox, border, dim -#include "ftxui/screen/color.hpp" // for Color, Color::Blue, Color::BlueLight, Color::Red, Color::Yellow +#include "ftxui/component/animation.hpp" // for ElasticOut, Linear +#include "ftxui/component/component.hpp" // for Menu, Horizontal, Renderer, Vertical +#include "ftxui/component/component_base.hpp" // for ComponentBase +#include "ftxui/component/component_options.hpp" // for MenuOption, MenuEntryOption, AnimatedColorOption, AnimatedColorsOption, UnderlineOption +#include "ftxui/component/mouse.hpp" // for ftxui +#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive +#include "ftxui/dom/elements.hpp" // for separator, operator|, Element, text, bgcolor, hbox, bold, color, filler, border, vbox, borderDouble, dim, flex, hcenter +#include "ftxui/screen/color.hpp" // for Color, Color::Red, Color::Black, Color::Yellow, Color::Blue, Color::Default, Color::White + +using namespace ftxui; + +Component VMenu1(std::vector* entries, int* selected); +Component VMenu2(std::vector* entries, int* selected); +Component VMenu3(std::vector* entries, int* selected); +Component VMenu4(std::vector* entries, int* selected); +Component VMenu5(std::vector* entries, int* selected); +Component VMenu6(std::vector* entries, int* selected); +Component VMenu7(std::vector* entries, int* selected); +Component VMenu8(std::vector* entries, int* selected); +Component HMenu1(std::vector* entries, int* selected); +Component HMenu2(std::vector* entries, int* selected); +Component HMenu3(std::vector* entries, int* selected); +Component HMenu4(std::vector* entries, int* selected); +Component HMenu5(std::vector* entries, int* selected); int main(int argc, const char* argv[]) { - using namespace ftxui; auto screen = ScreenInteractive::TerminalOutput(); std::vector entries = { - "Monkey", "Dog", "Cat", "Bird", "Elephant", + "Monkey", "Dog", "Cat", "Bird", "Elephant", "Cat", }; - 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; + std::array selected = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - MenuOption option_1; - option_1.style_focused = bold | color(Color::Blue); - option_1.style_selected = color(Color::Blue); - option_1.style_selected_focused = bold | color(Color::Blue); - option_1.on_enter = screen.ExitLoopClosure(); - auto menu_1_ = Menu(&entries, &menu_1_selected_, &option_1); + auto vmenu_1_ = VMenu1(&entries, &selected[0]); + auto vmenu_2_ = VMenu2(&entries, &selected[1]); + auto vmenu_3_ = VMenu3(&entries, &selected[2]); + auto vmenu_4_ = VMenu4(&entries, &selected[3]); + auto vmenu_5_ = VMenu5(&entries, &selected[4]); + auto vmenu_6_ = VMenu6(&entries, &selected[5]); + auto vmenu_7_ = VMenu7(&entries, &selected[6]); + auto vmenu_8_ = VMenu8(&entries, &selected[7]); - MenuOption option_2; - option_2.style_focused = bold | color(Color::Blue); - option_2.style_selected = color(Color::Blue); - option_2.style_selected_focused = bold | color(Color::Blue); - option_2.on_enter = screen.ExitLoopClosure(); - auto menu_2_ = Menu(&entries, &menu_2_selected_, &option_2); + auto hmenu_1_ = HMenu1(&entries, &selected[8]); + auto hmenu_2_ = HMenu2(&entries, &selected[9]); + auto hmenu_3_ = HMenu3(&entries, &selected[10]); + auto hmenu_4_ = HMenu4(&entries, &selected[11]); + auto hmenu_5_ = HMenu5(&entries, &selected[12]); - MenuOption option_3; - option_3.style_selected = color(Color::Blue); - option_3.style_focused = bgcolor(Color::Blue); - option_3.style_selected_focused = bgcolor(Color::Blue); - option_3.on_enter = screen.ExitLoopClosure(); - auto menu_3_ = Menu(&entries, &menu_3_selected_, &option_3); - - MenuOption option_4; - option_4.style_selected = bgcolor(Color::Blue); - option_4.style_focused = bgcolor(Color::BlueLight); - option_4.style_selected_focused = bgcolor(Color::BlueLight); - option_4.on_enter = screen.ExitLoopClosure(); - auto menu_4_ = Menu(&entries, &menu_4_selected_, &option_4); - - MenuOption option_5; - option_5.style_normal = bgcolor(Color::Blue); - option_5.style_selected = bgcolor(Color::Yellow); - option_5.style_focused = bgcolor(Color::Red); - option_5.style_selected_focused = bgcolor(Color::Red); - option_5.on_enter = screen.ExitLoopClosure(); - auto menu_5_ = Menu(&entries, &menu_5_selected_, &option_5); - - MenuOption option_6; - option_6.style_normal = dim | color(Color::Blue); - option_6.style_selected = color(Color::Blue); - option_6.style_focused = bold | color(Color::Blue); - option_6.style_selected_focused = bold | color(Color::Blue); - option_6.on_enter = screen.ExitLoopClosure(); - auto menu_6_ = Menu(&entries, &menu_6_selected_, &option_6); - - auto container = Container::Horizontal({ - menu_1_, - menu_2_, - menu_3_, - menu_4_, - menu_5_, - menu_6_, + auto container = Container::Vertical({ + Container::Horizontal({ + vmenu_1_, + vmenu_2_, + vmenu_3_, + vmenu_4_, + vmenu_5_, + vmenu_6_, + vmenu_7_, + vmenu_8_, + }), + hmenu_1_, + hmenu_2_, + hmenu_3_, + hmenu_4_, + hmenu_5_, }); - // clang-format off auto renderer = Renderer(container, [&] { - 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, - }) | border; + return // + hbox({ + vbox({ + hbox({ + vmenu_1_->Render(), + separator(), + vmenu_2_->Render(), + separator(), + vmenu_3_->Render(), + separator(), + vmenu_4_->Render(), + separator(), + vmenu_5_->Render(), + vmenu_6_->Render(), + separator(), + vmenu_7_->Render(), + separator(), + vmenu_8_->Render(), + }), + separator(), + hmenu_1_->Render(), + separator(), + hmenu_2_->Render(), + separator(), + hmenu_3_->Render(), + separator(), + hmenu_4_->Render(), + hmenu_5_->Render(), + }) | border, + filler(), + }); }); - // clang-format on screen.Loop(renderer); } +Component VMenu1(std::vector* entries, int* selected) { + auto option = MenuOption::Vertical(); + option.entries.transform = [](EntryState state) { + state.label = (state.active ? "> " : " ") + state.label; + Element e = text(state.label); + if (state.focused) + e = e | bgcolor(Color::Blue); + if (state.active) + e = e | bold; + return e; + }; + return Menu(entries, selected, option); +} + +Component VMenu2(std::vector* entries, int* selected) { + auto option = MenuOption::Vertical(); + option.entries.transform = [](EntryState state) { + state.label += (state.active ? " <" : " "); + Element e = hbox(filler(), text(state.label)); + if (state.focused) + e = e | bgcolor(Color::Red); + if (state.active) + e = e | bold; + return e; + }; + return Menu(entries, selected, option); +} + +Component VMenu3(std::vector* entries, int* selected) { + auto option = MenuOption::Vertical(); + option.entries.transform = [](EntryState state) { + Element e = state.active ? text("[" + state.label + "]") + : text(" " + state.label + " "); + if (state.focused) + e = e | bold; + + if (state.focused) + e = e | color(Color::Blue); + if (state.active) + e = e | bold; + return e; + }; + return Menu(entries, selected, option); +} + +Component VMenu4(std::vector* entries, int* selected) { + auto option = MenuOption::Vertical(); + option.entries.transform = [](EntryState state) { + if (state.active && state.focused) { + return text(state.label) | color(Color::Yellow) | bgcolor(Color::Black) | + bold; + } + + if (state.active) { + return text(state.label) | color(Color::Yellow) | bgcolor(Color::Black); + } + if (state.focused) { + return text(state.label) | color(Color::Black) | bgcolor(Color::Yellow) | + bold; + } + return text(state.label) | color(Color::Black) | bgcolor(Color::Yellow); + }; + return Menu(entries, selected, option); +} + +Component VMenu5(std::vector* entries, int* selected) { + auto option = MenuOption::Vertical(); + option.entries.transform = [](EntryState state) { + auto element = text(state.label); + if (state.active && state.focused) { + return element | borderDouble; + } + if (state.active) { + return element | border; + } + if (state.focused) { + return element | bold; + } + return element; + }; + return Menu(entries, selected, option); +} + +Component VMenu6(std::vector* entries, int* selected) { + auto option = MenuOption::VerticalAnimated(); + option.underline.color_inactive = Color::Default; + option.underline.color_active = Color::Red; + option.underline.SetAnimationFunction(animation::easing::Linear); + return Menu(entries, selected, option); +} + +Component VMenu7(std::vector* entries, int* selected) { + auto option = MenuOption::Vertical(); + option.entries.animated_colors.foreground.enabled = true; + option.entries.animated_colors.background.enabled = true; + option.entries.animated_colors.background.active = Color::Red; + option.entries.animated_colors.background.inactive = Color::Black; + option.entries.animated_colors.foreground.active = Color::White; + option.entries.animated_colors.foreground.inactive = Color::Red; + return Menu(entries, selected, option); +} + +Component VMenu8(std::vector* entries, int* selected) { + auto option = MenuOption::Vertical(); + option.entries.animated_colors.foreground.Set(Color::Red, Color::White, + std::chrono::milliseconds(500)); + return Menu(entries, selected, option); +} + +Component HMenu1(std::vector* entries, int* selected) { + return Menu(entries, selected, MenuOption::Horizontal()); +} + +Component HMenu2(std::vector* entries, int* selected) { + return Menu(entries, selected, MenuOption::Toggle()); +} + +Component HMenu3(std::vector* entries, int* selected) { + auto option = MenuOption::Toggle(); + option.elements_infix = [] { return text(" 🮣🮠 "); }; + + return Menu(entries, selected, option); +} + +Component HMenu4(std::vector* entries, int* selected) { + return Menu(entries, selected, MenuOption::HorizontalAnimated()); +} + +Component HMenu5(std::vector* entries, int* selected) { + auto option = MenuOption::HorizontalAnimated(); + option.underline.SetAnimation(std::chrono::milliseconds(1500), + animation::easing::ElasticOut); + option.entries.transform = [](EntryState state) { + Element e = text(state.label) | hcenter | flex; + if (state.active && state.focused) + e = e | bold; + if (!state.focused && !state.active) + e = e | dim; + return e; + }; + option.underline.color_inactive = Color::Default; + option.underline.color_active = Color::Red; + return Menu(entries, selected, option); +} + // 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/examples/component/menu_underline_animated_gallery.cpp b/examples/component/menu_underline_animated_gallery.cpp new file mode 100644 index 0000000..e143b8f --- /dev/null +++ b/examples/component/menu_underline_animated_gallery.cpp @@ -0,0 +1,94 @@ +#include // for operator""ms, literals +#include // for shared_ptr, __shared_ptr_access, allocator +#include // for string, basic_string, operator+, to_string +#include // for vector + +#include "ftxui/component/animation.hpp" // for BackOut, Duration +#include "ftxui/component/component.hpp" // for Menu, Renderer, Vertical +#include "ftxui/component/component_base.hpp" // for ComponentBase +#include "ftxui/component/component_options.hpp" // for MenuOption, UnderlineOption +#include "ftxui/component/mouse.hpp" // for ftxui +#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive +#include "ftxui/dom/elements.hpp" // for text, Element, operator|, borderEmpty, inverted +#include "ftxui/screen/color.hpp" // for Color, Color::Blue, Color::Red + +using namespace ftxui; + +Component DummyComponent(int id) { + return Renderer([id](bool focused) { + auto t = text("component " + std::to_string(id)); + if (focused) + t = t | inverted; + return t; + }); +} + +Component Text(const std::string& t) { + return Renderer([t] { return text(t) | borderEmpty; }); +} + +int main(int argc, const char* argv[]) { + using namespace std::literals; + std::vector tab_values{ + "Tab 1", "Tab 2", "Tab 3", "A very very long tab", "탭", + }; + int tab_selected = 0; + + auto container = Container::Vertical({}); + + int frame_count = 0; + container->Add(Renderer( + [&] { return text("Frame count: " + std::to_string(frame_count++)); })); + + { + auto option = MenuOption::HorizontalAnimated(); + container->Add(Text("This demonstrate the Menu component")); + container->Add(Menu(&tab_values, &tab_selected, option)); + } + + { + container->Add(Text("Set underline color to blue")); + auto option = MenuOption::HorizontalAnimated(); + option.underline.color_inactive = Color::Blue; + container->Add(Menu(&tab_values, &tab_selected, option)); + } + + { + container->Add(Text("Set underline active color to red")); + auto option = MenuOption::HorizontalAnimated(); + option.underline.color_active = Color::Red; + container->Add(Menu(&tab_values, &tab_selected, option)); + } + + { + container->Add(Text("Set animation duration to 0ms")); + auto option = MenuOption::HorizontalAnimated(); + option.underline.SetAnimationDuration(0ms); + container->Add(Menu(&tab_values, &tab_selected, option)); + } + + { + container->Add(Text("Set animation easing function to back-out")); + auto option = MenuOption::HorizontalAnimated(); + option.underline.SetAnimationFunction(animation::easing::BackOut); + option.underline.SetAnimationDuration(350ms); + container->Add(Menu(&tab_values, &tab_selected, option)); + } + + // option.underline_animation_follower_delay = 250ms + { + container->Add(Text("Add delay to desynchronize animation")); + auto option = MenuOption::HorizontalAnimated(); + option.underline.follower_delay = 250ms; + container->Add(Menu(&tab_values, &tab_selected, option)); + } + + container->SetActiveChild(container->ChildAt(2)); + + auto screen = ScreenInteractive::TerminalOutput(); + screen.Loop(container); +} + +// 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/examples/dom/color_gallery.cpp b/examples/dom/color_gallery.cpp index 48c0aca..be23829 100644 --- a/examples/dom/color_gallery.cpp +++ b/examples/dom/color_gallery.cpp @@ -5,12 +5,13 @@ #include // for move #include // for vector -using namespace ftxui; -#include "./color_info_sorted_2d.ipp" // for ColorInfoSorted2D #include "ftxui/dom/elements.hpp" // for text, bgcolor, color, vbox, hbox, separator, operator|, Elements, Element, Fit, border #include "ftxui/dom/node.hpp" // for Render #include "ftxui/screen/color.hpp" // for Color, Color::Black, Color::Blue, Color::BlueLight, Color::Cyan, Color::CyanLight, Color::Default, Color::GrayDark, Color::GrayLight, Color::Green, Color::GreenLight, Color::Magenta, Color::MagentaLight, Color::Red, Color::RedLight, Color::White, Color::Yellow, Color::YellowLight, Color::Palette256, ftxui +using namespace ftxui; +#include "./color_info_sorted_2d.ipp" // for ColorInfoSorted2D + int main(int argc, const char* argv[]) { // clang-format off auto basic_color_display = diff --git a/examples/dom/color_info_sorted_2d.ipp b/examples/dom/color_info_sorted_2d.ipp index 2bf8c23..910f165 100644 --- a/examples/dom/color_info_sorted_2d.ipp +++ b/examples/dom/color_info_sorted_2d.ipp @@ -1,12 +1,13 @@ -#include #include +#include +#include // for ftxui::ColorInfo -std::vector> ColorInfoSorted2D() { +std::vector> ColorInfoSorted2D() { // Acquire the color information for the palette256. - std::vector info_gray; - std::vector info_color; + std::vector info_gray; + std::vector info_color; for (int i = 16; i < 256; ++i) { - ColorInfo info = GetColorInfo(Color::Palette256(i)); + ftxui::ColorInfo info = GetColorInfo(ftxui::Color::Palette256(i)); if (info.saturation == 0) info_gray.push_back(info); else @@ -16,10 +17,10 @@ std::vector> ColorInfoSorted2D() { // Sort info_color by hue. std::sort( info_color.begin(), info_color.end(), - [](const ColorInfo& A, const ColorInfo& B) { return A.hue < B.hue; }); + [](const ftxui::ColorInfo& A, const ftxui::ColorInfo& B) { return A.hue < B.hue; }); // Make 8 colums, one gray and seven colored. - std::vector> info_columns(8); + std::vector> info_columns(8); info_columns[0] = info_gray; for (size_t i = 0; i < info_color.size(); ++i) { info_columns[1 + 7 * i / info_color.size()].push_back(info_color[i]); @@ -28,7 +29,7 @@ std::vector> ColorInfoSorted2D() { // Minimize discontinuities for every columns. for (auto& column : info_columns) { std::sort(column.begin(), column.end(), - [](const ColorInfo& A, const ColorInfo& B) { + [](const ftxui::ColorInfo& A, const ftxui::ColorInfo& B) { return A.value < B.value; }); for (int i = 0; i < int(column.size()) - 1; ++i) { diff --git a/examples/index.html b/examples/index.html index 13212b3..5ed2ae5 100644 --- a/examples/index.html +++ b/examples/index.html @@ -2,7 +2,8 @@ FTXUI examples WebAssembly - + + @@ -56,10 +57,11 @@ stdout_buffer.push(code) } } - let stderr = code => console.log(code); - var term = new Terminal(); + const stderr = code => console.log(code); + const term = new Terminal(); term.open(document.querySelector('#terminal')); term.resize(140,43); + term.loadAddon(new (WebglAddon.WebglAddon)()); const onBinary = e => { for(c of e) stdin_buffer.push(c.charCodeAt(0)); @@ -78,6 +80,7 @@