From aebde943523bb75da79ba45eb5b2e88d39a620e1 Mon Sep 17 00:00:00 2001 From: Arthur Sonzogni Date: Thu, 31 Mar 2022 02:17:43 +0200 Subject: [PATCH] Add clang-tidy. (#368) --- .clang-tidy | 22 ++ CMakeLists.txt | 2 + cmake/ftxui_set_options.cmake | 13 + examples/CMakeLists.txt | 3 + examples/component/checkbox_in_frame.cpp | 5 +- examples/component/menu_entries.cpp | 2 +- examples/component/menu_style.cpp | 4 +- examples/dom/border.cpp | 4 +- examples/dom/color_gallery.cpp | 18 +- examples/dom/graph.cpp | 55 ++-- examples/dom/window.cpp | 33 +- examples/index.html | 20 +- include/ftxui/component/component.hpp | 2 +- include/ftxui/component/component_options.hpp | 26 +- include/ftxui/component/event.hpp | 2 +- include/ftxui/dom/canvas.hpp | 7 +- include/ftxui/dom/deprecated.hpp | 6 +- include/ftxui/dom/elements.hpp | 38 +-- include/ftxui/dom/flexbox_config.hpp | 2 +- include/ftxui/dom/node.hpp | 9 +- include/ftxui/dom/requirement.hpp | 2 +- include/ftxui/dom/table.hpp | 8 +- include/ftxui/dom/take_any_args.hpp | 7 +- include/ftxui/screen/box.hpp | 6 +- include/ftxui/screen/color.hpp | 18 +- include/ftxui/screen/color_info.hpp | 4 +- include/ftxui/screen/deprecated.hpp | 2 +- include/ftxui/screen/screen.hpp | 15 +- include/ftxui/screen/terminal.hpp | 6 +- src/ftxui/component/animation.cpp | 134 ++++---- src/ftxui/component/button.cpp | 36 ++- src/ftxui/component/catch_event.cpp | 11 +- src/ftxui/component/checkbox.cpp | 22 +- src/ftxui/component/collapsible.cpp | 27 +- src/ftxui/component/component.cpp | 44 +-- src/ftxui/component/component_options.cpp | 114 +++---- src/ftxui/component/container.cpp | 98 ++++-- src/ftxui/component/dropdown.cpp | 29 +- src/ftxui/component/event.cpp | 61 ++-- src/ftxui/component/input.cpp | 60 ++-- src/ftxui/component/maybe.cpp | 8 +- src/ftxui/component/menu.cpp | 172 +++++++---- src/ftxui/component/radiobox.cpp | 64 ++-- src/ftxui/component/renderer.cpp | 13 +- src/ftxui/component/resizable_split.cpp | 44 ++- src/ftxui/component/screen_interactive.cpp | 118 +++++--- src/ftxui/component/slider.cpp | 7 +- src/ftxui/component/terminal_input_parser.cpp | 155 ++++++---- src/ftxui/component/terminal_input_parser.hpp | 2 +- src/ftxui/component/util.cpp | 12 +- src/ftxui/dom/border.cpp | 151 +++++---- src/ftxui/dom/box_helper.cpp | 19 +- src/ftxui/dom/canvas.cpp | 134 ++++---- src/ftxui/dom/clear_under.cpp | 4 +- src/ftxui/dom/dbox.cpp | 5 +- src/ftxui/dom/flex.cpp | 5 +- src/ftxui/dom/flexbox.cpp | 25 +- src/ftxui/dom/flexbox_helper.cpp | 143 +++++---- src/ftxui/dom/focus.cpp | 14 +- src/ftxui/dom/frame.cpp | 2 +- src/ftxui/dom/gauge.cpp | 72 +++-- src/ftxui/dom/graph.cpp | 13 +- src/ftxui/dom/gridbox.cpp | 25 +- src/ftxui/dom/hbox.cpp | 4 +- src/ftxui/dom/node.cpp | 16 +- src/ftxui/dom/paragraph.cpp | 25 +- src/ftxui/dom/scroll_indicator.cpp | 14 +- src/ftxui/dom/separator.cpp | 91 +++--- src/ftxui/dom/size.cpp | 3 +- src/ftxui/dom/spinner.cpp | 33 +- src/ftxui/dom/table.cpp | 94 +++--- src/ftxui/dom/text.cpp | 27 +- src/ftxui/dom/util.cpp | 18 +- src/ftxui/dom/vbox.cpp | 4 +- src/ftxui/screen/box.cpp | 2 +- src/ftxui/screen/color.cpp | 227 +++++++------- src/ftxui/screen/color_info.cpp | 11 +- src/ftxui/screen/screen.cpp | 173 +++++++---- src/ftxui/screen/string.cpp | 286 ++++++++++-------- src/ftxui/screen/terminal.cpp | 116 +++---- 80 files changed, 1955 insertions(+), 1373 deletions(-) create mode 100644 .clang-tidy diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 000000000..6459e5914 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,22 @@ +--- +Checks: "*, + -abseil-*, + -altera-*, + -android-*, + -fuchsia-*, + -google-*, + -llvm*, + -modernize-use-trailing-return-type, + -zircon-*, + -readability-else-after-return, + -readability-static-accessed-through-instance, + -readability-avoid-const-params-in-decls, + -cppcoreguidelines-non-private-member-variables-in-classes, + -misc-non-private-member-variables-in-classes, + -modernize-use-nodiscard, + -misc-no-recursion, + -readability-implicit-bool-conversion, +" +WarningsAsErrors: '' +HeaderFilterRegex: '' +FormatStyle: none diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e5091e8d..b5ce56694 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ option(FTXUI_BUILD_EXAMPLES "Set to ON to build examples" ON) option(FTXUI_BUILD_TESTS "Set to ON to build tests" OFF) option(FTXUI_BUILD_TESTS_FUZZER "Set to ON to enable fuzzing" OFF) option(FTXUI_ENABLE_INSTALL "Generate the install target" ON) +option(FTXUI_CLANG_TIDY "Execute clang-tidy" OFF) set(FTXUI_MICROSOFT_TERMINAL_FALLBACK_HELP_TEXT "On windows, assume the \ terminal used will be one of Microsoft and use a set of reasonnable fallback \ @@ -22,6 +23,7 @@ else() ${FTXUI_MICROSOFT_TERMINAL_FALLBACK_HELP_TEXT} OFF) endif() + add_library(screen include/ftxui/screen/box.hpp include/ftxui/screen/color.hpp diff --git a/cmake/ftxui_set_options.cmake b/cmake/ftxui_set_options.cmake index 46e806c7f..7017639e0 100644 --- a/cmake/ftxui_set_options.cmake +++ b/cmake/ftxui_set_options.cmake @@ -1,6 +1,19 @@ +find_program( CLANG_TIDY_EXE NAMES "clang-tidy" DOC "Path to clang-tidy executable" ) +if(NOT CLANG_TIDY_EXE) + message(STATUS "clang-tidy not found.") +else() + message(STATUS "clang-tidy found: ${CLANG_TIDY_EXE}") +endif() + + function(ftxui_set_options library) set_target_properties(${library} PROPERTIES OUTPUT_NAME "ftxui-${library}") + if(CLANG_TIDY_EXE AND FTXUI_CLANG_TIDY) + set_target_properties(${library} + PROPERTIES CXX_CLANG_TIDY "${CLANG_TIDY_EXE};-warnings-as-errors=*" + ) + endif() target_include_directories(${library} PUBLIC diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 92a61620a..74f295d76 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -12,6 +12,9 @@ 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") + target_link_options(component PUBLIC "SHELL: -s ASSERTIONS=1") + #string(APPEND CMAKE_EXE_LINKER_FLAGS " -s ALLOW_MEMORY_GROWTH=1") + #target_link_options(component PUBLIC "SHELL: -s ALLOW_MEMORY_GROWTH=1") get_property(EXAMPLES GLOBAL PROPERTY FTXUI::EXAMPLES) foreach(file diff --git a/examples/component/checkbox_in_frame.cpp b/examples/component/checkbox_in_frame.cpp index 92bf4e6fc..54cd43c9c 100644 --- a/examples/component/checkbox_in_frame.cpp +++ b/examples/component/checkbox_in_frame.cpp @@ -1,13 +1,12 @@ #include // for array -#include // for shared_ptr, __shared_ptr_access, allocator_traits<>::value_type +#include // for shared_ptr, __shared_ptr_access #include // for operator+, to_string -#include // for vector #include "ftxui/component/captured_mouse.hpp" // for ftxui #include "ftxui/component/component.hpp" // for Checkbox, Renderer, 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, size, border, frame, HEIGHT, LESS_THAN +#include "ftxui/dom/elements.hpp" // for operator|, Element, size, border, frame, vscroll_indicator, HEIGHT, LESS_THAN using namespace ftxui; diff --git a/examples/component/menu_entries.cpp b/examples/component/menu_entries.cpp index 648c8e224..4f9ca9e15 100644 --- a/examples/component/menu_entries.cpp +++ b/examples/component/menu_entries.cpp @@ -17,7 +17,7 @@ using namespace ftxui; MenuEntryOption Colored(ftxui::Color c) { MenuEntryOption option; option.transform = [c](EntryState state) { - state.label = (state.active? "> " : " ") + state.label; + state.label = (state.active ? "> " : " ") + state.label; Element e = text(state.label) | color(c); if (state.focused) e = e | inverted; diff --git a/examples/component/menu_style.cpp b/examples/component/menu_style.cpp index b4e92cf10..3d0ecf3b1 100644 --- a/examples/component/menu_style.cpp +++ b/examples/component/menu_style.cpp @@ -33,7 +33,7 @@ Component HMenu5(std::vector* entries, int* selected); int main(int argc, const char* argv[]) { auto screen = ScreenInteractive::TerminalOutput(); - std::vector entries = { + std::vector entries{ "Monkey", "Dog", "Cat", "Bird", "Elephant", "Cat", }; std::array selected = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; @@ -140,7 +140,7 @@ 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 + " "); + : text(" " + state.label + " "); if (state.focused) e = e | bold; diff --git a/examples/dom/border.cpp b/examples/dom/border.cpp index c3cc9bc04..78b9135ee 100644 --- a/examples/dom/border.cpp +++ b/examples/dom/border.cpp @@ -1,3 +1,4 @@ +#include // for EXIT_SUCCESS #include // for text, operator|, vbox, border, Element, Fit, hbox #include // for Full, Screen #include // for allocator @@ -5,7 +6,7 @@ #include "ftxui/dom/node.hpp" // for Render #include "ftxui/screen/color.hpp" // for ftxui -int main(int argc, const char* argv[]) { +int main() { using namespace ftxui; auto document = // hbox({ @@ -30,6 +31,7 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); screen.Print(); + return EXIT_SUCCESS; } // Copyright 2020 Arthur Sonzogni. All rights reserved. diff --git a/examples/dom/color_gallery.cpp b/examples/dom/color_gallery.cpp index be23829ab..fc8f584c1 100644 --- a/examples/dom/color_gallery.cpp +++ b/examples/dom/color_gallery.cpp @@ -12,7 +12,7 @@ using namespace ftxui; #include "./color_info_sorted_2d.ipp" // for ColorInfoSorted2D -int main(int argc, const char* argv[]) { +int main() { // clang-format off auto basic_color_display = vbox( @@ -83,14 +83,18 @@ int main(int argc, const char* argv[]) { // True color display. auto true_color_display = text("TrueColors: 24bits:"); { - int saturation = 255; + const int max_value = 255; + const int value_increment = 8; + const int hue_increment = 6; + int saturation = max_value; Elements array; - for (int value = 0; value < 255; value += 16) { + for (int value = 0; value < max_value; value += 2 * value_increment) { 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))); + for (int hue = 0; hue < max_value; hue += hue_increment) { + line.push_back( + text("▀") // + | color(Color::HSV(hue, saturation, value)) // + | bgcolor(Color::HSV(hue, saturation, value + value_increment))); } array.push_back(hbox(std::move(line))); } diff --git a/examples/dom/graph.cpp b/examples/dom/graph.cpp index 4bb9a0585..536733059 100644 --- a/examples/dom/graph.cpp +++ b/examples/dom/graph.cpp @@ -1,9 +1,10 @@ #include // for operator""s, chrono_literals #include // for sin -#include // for operator|, graph, separator, color, Element, vbox, flex, inverted, Fit, hbox, size, border, GREATER_THAN, HEIGHT +#include // for graph, operator|, separator, color, Element, vbox, flex, inverted, operator|=, Fit, hbox, size, border, GREATER_THAN, HEIGHT #include // for Full, Screen #include // for ref, reference_wrapper #include // for cout, ostream +#include // for shared_ptr #include // for operator<<, string #include // for sleep_for #include // for vector @@ -13,15 +14,15 @@ class Graph { public: - std::vector operator()(int width, int height) { + std::vector operator()(int width, int height) const { std::vector output(width); for (int i = 0; i < width; ++i) { float v = 0; - v += 0.1f * sin((i + shift) * 0.1f); - v += 0.2f * sin((i + shift + 10) * 0.15f); - v += 0.1f * sin((i + shift) * 0.03f); - v *= height; - v += 0.5f * height; + v += 0.1f * sin((i + shift) * 0.1f); // NOLINT + v += 0.2f * sin((i + shift + 10) * 0.15f); // NOLINT + v += 0.1f * sin((i + shift) * 0.03f); // NOLINT + v *= height; // NOLINT + v += 0.5f * height; // NOLINT output[i] = static_cast(v); } return output; @@ -37,7 +38,7 @@ std::vector triangle(int width, int height) { return output; } -int main(int argc, const char* argv[]) { +int main() { using namespace ftxui; using namespace std::chrono_literals; @@ -45,23 +46,26 @@ int main(int argc, const char* argv[]) { std::string reset_position; for (int i = 0;; ++i) { - auto document = - hbox({ - vbox({ - graph(std::ref(my_graph)), - separator(), - graph(triangle) | inverted, - }) | flex, + auto document = hbox({ + vbox({ + graph(std::ref(my_graph)), separator(), - vbox({ - graph(std::ref(my_graph)) | color(Color::BlueLight), - separator(), - graph(std::ref(my_graph)) | color(Color::RedLight), - separator(), - graph(std::ref(my_graph)) | color(Color::YellowLight), - }) | flex, - }) | - border | size(HEIGHT, GREATER_THAN, 40); + graph(triangle) | inverted, + }) | flex, + separator(), + vbox({ + graph(std::ref(my_graph)) | color(Color::BlueLight), + separator(), + graph(std::ref(my_graph)) | color(Color::RedLight), + separator(), + graph(std::ref(my_graph)) | color(Color::YellowLight), + }) | flex, + }); + + document |= border; + + const int min_width = 40; + document |= size(HEIGHT, GREATER_THAN, min_width); auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); @@ -69,7 +73,8 @@ int main(int argc, const char* argv[]) { screen.Print(); reset_position = screen.ResetPosition(); - std::this_thread::sleep_for(0.03s); + const auto sleep_time = 0.03s; + std::this_thread::sleep_for(sleep_time); my_graph.shift++; } diff --git a/examples/dom/window.cpp b/examples/dom/window.cpp index 6de7ee1dd..ed0e2b934 100644 --- a/examples/dom/window.cpp +++ b/examples/dom/window.cpp @@ -1,25 +1,32 @@ -#include // for operator|, color, Element, bgcolor, graph, border +#include // for EXIT_SUCCESS +#include // for operator|=, Element, bgcolor, color, graph, border #include // for Fixed, Screen #include // for vector -#include "ftxui/dom/node.hpp" // for Render -#include "ftxui/screen/color.hpp" // for Color, Color::DarkBlue, Color::Green, Color::Red, ftxui +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/color.hpp" // for Color, Color::DarkBlue, Color::Red, ftxui -int main(void) { +int main() { using namespace ftxui; Element document = graph([](int x, int y) { - std::vector result(x, 0); - for (int i{0}; i < x; ++i) { - result[i] = ((3 * i) / 2) % y; - } - return result; - }) | - color(Color::Red) | border | color(Color::Green) | - bgcolor(Color::DarkBlue); + std::vector result(x, 0); + for (int i{0}; i < x; ++i) { + result[i] = ((3 * i) / 2) % y; + } + return result; + }); - auto screen = Screen::Create(Dimension::Fixed(80), Dimension::Fixed(10)); + document |= color(Color::Red); + document |= bgcolor(Color::DarkBlue); + document |= border; + + const int width = 80; + const int height = 10; + auto screen = + Screen::Create(Dimension::Fixed(width), Dimension::Fixed(height)); Render(screen, document); screen.Print(); + return EXIT_SUCCESS; } // Copyright 2020 Arthur Sonzogni. All rights reserved. diff --git a/examples/index.html b/examples/index.html index 5ed2ae530..717a5fe3d 100644 --- a/examples/index.html +++ b/examples/index.html @@ -44,12 +44,12 @@

FTXUI WebAssembly Example

}); let stdin_buffer = []; - let stdin = () => { + const stdin = () => { return stdin_buffer.shift() || 0; } - stdout_buffer = []; - let stdout = code => { + let stdout_buffer = []; + const stdout = code => { if (code == 0) { term.write(new Uint8Array(stdout_buffer)); stdout_buffer = []; @@ -57,7 +57,15 @@

FTXUI WebAssembly Example

stdout_buffer.push(code) } } - const stderr = code => console.log(code); + let stderrbuffer = []; + const stderr = code => { + if (code == 0 || code == 10) { + console.error(String.fromCodePoint(...stderrbuffer)); + stderrbuffer = []; + } else { + stderrbuffer.push(code) + } + } const term = new Terminal(); term.open(document.querySelector('#terminal')); term.resize(140,43); @@ -69,7 +77,9 @@

FTXUI WebAssembly Example

term.onBinary(onBinary); term.onData(onBinary) window.Module = { - preRun: () => { FS.init(stdin, stdout, stderr); }, + preRun: () => { + FS.init(stdin, stdout, stderr); + }, postRun: [], onRuntimeInitialized: () => {}, }; diff --git a/include/ftxui/component/component.hpp b/include/ftxui/component/component.hpp index ae1c8e15d..e36ab35bd 100644 --- a/include/ftxui/component/component.hpp +++ b/include/ftxui/component/component.hpp @@ -8,7 +8,7 @@ #include // for vector #include "ftxui/component/component_base.hpp" // for Component, Components -#include "ftxui/component/component_options.hpp" // for ButtonOption, CheckboxOption (ptr only), InputOption (ptr only), MenuEntryOption (ptr only), MenuOption, RadioboxOption (ptr only) +#include "ftxui/component/component_options.hpp" // for ButtonOption, CheckboxOption, InputOption (ptr only), MenuEntryOption (ptr only), MenuOption, RadioboxOption (ptr only) #include "ftxui/dom/elements.hpp" // for Element #include "ftxui/util/ref.hpp" // for Ref, ConstStringRef, ConstStringListRef, StringRef diff --git a/include/ftxui/component/component_options.hpp b/include/ftxui/component/component_options.hpp index d5f532796..7b02f0f9e 100644 --- a/include/ftxui/component/component_options.hpp +++ b/include/ftxui/component/component_options.hpp @@ -3,11 +3,11 @@ #include // for milliseconds #include // for Duration, QuadraticInOut, Function -#include // for Decorator, bold, inverted, operator|, Element, nothing -#include // for Ref -#include // for function -#include // for optional -#include // for string, allocator +#include // for Element +#include // for Ref +#include // for function +#include // for optional +#include // for string #include "ftxui/screen/color.hpp" // for Color, Color::GrayDark, Color::White @@ -17,10 +17,10 @@ namespace ftxui { /// |Radiobox::transform|, |MenuEntryOption::transform|, /// |MenuOption::transform|. struct EntryState { - std::string label; /// < The label to display. - bool state; /// < The state of the button/checkbox/radiobox - bool active; /// < Whether the entry is the active one. - bool focused; /// < Whether the entry is one focused by the user. + std::string label; /// < The label to display. + bool state; /// < The state of the button/checkbox/radiobox + bool active; /// < Whether the entry is the active one. + bool focused; /// < Whether the entry is one focused by the user. }; struct UnderlineOption { @@ -70,7 +70,7 @@ struct AnimatedColorsOption { /// @brief Option for the MenuEntry component. /// @ingroup component struct MenuEntryOption { - std::function transform; + std::function transform; AnimatedColorsOption animated_colors; }; @@ -115,7 +115,7 @@ struct ButtonOption { Color foreground_active); // Style: - std::function transform; + std::function transform; AnimatedColorsOption animated_colors; }; @@ -126,7 +126,7 @@ struct CheckboxOption { static CheckboxOption Simple(); // Style: - std::function transform; + std::function transform; // Observer: /// Called when the user change the state. @@ -156,7 +156,7 @@ struct RadioboxOption { static RadioboxOption Simple(); // Style: - std::function transform; + std::function transform; // Observers: /// Called when the selected entry changes. diff --git a/include/ftxui/component/event.hpp b/include/ftxui/component/event.hpp index 0d356cfd0..d226c9c87 100644 --- a/include/ftxui/component/event.hpp +++ b/include/ftxui/component/event.hpp @@ -54,7 +54,7 @@ struct Event { static const Event PageDown; // --- Custom --- - static Event Custom; + static const Event Custom; //--- Method section --------------------------------------------------------- bool is_character() const { return type_ == Type::Character; } diff --git a/include/ftxui/dom/canvas.hpp b/include/ftxui/dom/canvas.hpp index addf16bd5..02ed4a99e 100644 --- a/include/ftxui/dom/canvas.hpp +++ b/include/ftxui/dom/canvas.hpp @@ -1,7 +1,7 @@ #ifndef FTXUI_DOM_CANVAS_HPP #define FTXUI_DOM_CANVAS_HPP -#include // for size_t +#include // for size_t #include // for function #include // for string #include // for unordered_map @@ -13,7 +13,7 @@ namespace ftxui { struct Canvas { public: - Canvas() {} + Canvas() = default; Canvas(int width, int height); // Getters: @@ -114,7 +114,8 @@ struct Canvas { struct XYHash { size_t operator()(const XY& xy) const { - return static_cast(xy.x * 1024 + xy.y); + constexpr size_t shift = 1024; + return size_t(xy.x) * shift + size_t(xy.y); } }; diff --git a/include/ftxui/dom/deprecated.hpp b/include/ftxui/dom/deprecated.hpp index 7f537cd7f..497bfa164 100644 --- a/include/ftxui/dom/deprecated.hpp +++ b/include/ftxui/dom/deprecated.hpp @@ -1,5 +1,5 @@ -#ifndef FTXUI_DOM_DEPRECRATED_HPP -#define FTXUI_DOM_DEPRECRATED_HPP +#ifndef FTXUI_DOM_DEPRECATED_HPP +#define FTXUI_DOM_DEPRECATED_HPP #include "ftxui/dom/elements.hpp" @@ -9,7 +9,7 @@ Element vtext(std::wstring text); Elements paragraph(std::wstring text); } // namespace ftxui -#endif /* end of include guard: FTXUI_DOM_DEPRECRATED_HPP */ +#endif // FTXUI_DOM_DEPRECATED_HPP // Copyright 2021 Arthur Sonzogni. All rights reserved. // Use of this source code is governed by the MIT license that can be found in diff --git a/include/ftxui/dom/elements.hpp b/include/ftxui/dom/elements.hpp index 386be8c02..4d690a447 100644 --- a/include/ftxui/dom/elements.hpp +++ b/include/ftxui/dom/elements.hpp @@ -35,7 +35,7 @@ Decorator operator|(Decorator, Decorator); // --- Widget --- Element text(std::string text); Element vtext(std::string text); -Element separator(void); +Element separator(); Element separatorLight(); Element separatorHeavy(); Element separatorDouble(); @@ -45,18 +45,18 @@ Element separator(Pixel); Element separatorCharacter(std::string); Element separatorHSelector(float left, float right, - Color background, - Color foreground); + Color unselected_color, + Color selected_color); Element separatorVSelector(float up, float down, - Color background, - Color foreground); -Element gauge(float ratio); -Element gaugeLeft(float ratio); -Element gaugeRight(float ratio); -Element gaugeUp(float ratio); -Element gaugeDown(float ratio); -Element gaugeDirection(float ratio, GaugeDirection); + Color unselected_color, + Color selected_color); +Element gauge(float progress); +Element gaugeLeft(float progress); +Element gaugeRight(float progress); +Element gaugeUp(float progress); +Element gaugeDown(float progress); +Element gaugeDirection(float progress, GaugeDirection); Element border(Element); Element borderLight(Element); Element borderHeavy(Element); @@ -64,14 +64,14 @@ Element borderDouble(Element); Element borderRounded(Element); Element borderEmpty(Element); Decorator borderStyled(BorderStyle); -Decorator borderWith(Pixel); +Decorator borderWith(const Pixel&); Element window(Element title, Element content); Element spinner(int charset_index, size_t image_index); -Element paragraph(std::string text); -Element paragraphAlignLeft(std::string text); -Element paragraphAlignRight(std::string text); -Element paragraphAlignCenter(std::string text); -Element paragraphAlignJustify(std::string text); +Element paragraph(const std::string& text); +Element paragraphAlignLeft(const std::string& text); +Element paragraphAlignRight(const std::string& text); +Element paragraphAlignCenter(const std::string& text); +Element paragraphAlignJustify(const std::string& text); Element graph(GraphFunction); Element emptyElement(); Element canvas(ConstRef); @@ -90,7 +90,7 @@ Element color(Color, Element); Element bgcolor(Color, Element); Decorator focusPosition(int x, int y); Decorator focusPositionRelative(float x, float y); -Element automerge(Element); +Element automerge(Element child); // --- Layout is // Horizontal, Vertical or stacked set of elements. @@ -163,7 +163,7 @@ Dimensions Fit(Element&); // Include old definitions using wstring. #include "ftxui/dom/deprecated.hpp" -#endif /* end of include guard: FTXUI_DOM_ELEMENTS_HPP */ +#endif // FTXUI_DOM_ELEMENTS_HPP // Copyright 2020 Arthur Sonzogni. All rights reserved. // Use of this source code is governed by the MIT license that can be found in diff --git a/include/ftxui/dom/flexbox_config.hpp b/include/ftxui/dom/flexbox_config.hpp index 49a4b6ac2..15a73c964 100644 --- a/include/ftxui/dom/flexbox_config.hpp +++ b/include/ftxui/dom/flexbox_config.hpp @@ -108,7 +108,7 @@ struct FlexboxConfig { } // namespace ftxui -#endif /* end of include guard: FTXUI_DOM_FLEXBOX_CONFIG_HPP */ +#endif // FTXUI_DOM_FLEXBOX_CONFIG_HPP // Copyright 2021 Arthur Sonzogni. All rights reserved. // Use of this source code is governed by the MIT license that can be found in diff --git a/include/ftxui/dom/node.hpp b/include/ftxui/dom/node.hpp index 5bace34f9..34f7604b5 100644 --- a/include/ftxui/dom/node.hpp +++ b/include/ftxui/dom/node.hpp @@ -20,6 +20,11 @@ class Node { public: Node(); Node(Elements children); + Node(const Node&) = delete; + Node(const Node&&) = delete; + Node& operator=(const Node&) = delete; + Node& operator=(const Node&&) = delete; + virtual ~Node(); // Step 1: Compute layout requirement. Tell parent what dimensions this @@ -50,12 +55,12 @@ class Node { Box box_; }; -void Render(Screen& screen, const Element& node); +void Render(Screen& screen, const Element& element); void Render(Screen& screen, Node* node); } // namespace ftxui -#endif /* end of include guard: FTXUI_DOM_NODE_HPP */ +#endif // FTXUI_DOM_NODE_HPP // Copyright 2020 Arthur Sonzogni. All rights reserved. // Use of this source code is governed by the MIT license that can be found in diff --git a/include/ftxui/dom/requirement.hpp b/include/ftxui/dom/requirement.hpp index 8f7e8b83f..18b74d42a 100644 --- a/include/ftxui/dom/requirement.hpp +++ b/include/ftxui/dom/requirement.hpp @@ -28,7 +28,7 @@ struct Requirement { } // namespace ftxui -#endif /* end of include guard: FTXUI_DOM_REQUIREMENT_HPP */ +#endif // FTXUI_DOM_REQUIREMENT_HPP // Copyright 2020 Arthur Sonzogni. All rights reserved. // Use of this source code is governed by the MIT license that can be found in diff --git a/include/ftxui/dom/table.hpp b/include/ftxui/dom/table.hpp index 7c0e5340f..1d2a4e776 100644 --- a/include/ftxui/dom/table.hpp +++ b/include/ftxui/dom/table.hpp @@ -52,10 +52,10 @@ class Table { void Initialize(std::vector>); friend TableSelection; std::vector> elements_; - int input_dim_x_; - int input_dim_y_; - int dim_x_; - int dim_y_; + int input_dim_x_ = 0; + int input_dim_y_ = 0; + int dim_x_ = 0; + int dim_y_ = 0; }; class TableSelection { diff --git a/include/ftxui/dom/take_any_args.hpp b/include/ftxui/dom/take_any_args.hpp index eff64160d..136dab132 100644 --- a/include/ftxui/dom/take_any_args.hpp +++ b/include/ftxui/dom/take_any_args.hpp @@ -1,10 +1,13 @@ +#ifndef FTXUI_DOM_TAKE_ANY_ARGS_HPP +#define FTXUI_DOM_TAKE_ANY_ARGS_HPP + // IWYU pragma: private, include "ftxui/dom/elements.hpp" #include namespace ftxui { template -void Merge(Elements&, T) {} +void Merge(Elements& /*container*/, T /*element*/) {} template <> inline void Merge(Elements& container, Element element) { @@ -38,6 +41,8 @@ TAKE_ANY_ARGS(dbox) TAKE_ANY_ARGS(hflow) } // namespace ftxui +#endif // FTXUI_DOM_TAKE_ANY_ARGS_HPP + // 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/screen/box.hpp b/include/ftxui/screen/box.hpp index 75cff81a3..9edcd9e7a 100644 --- a/include/ftxui/screen/box.hpp +++ b/include/ftxui/screen/box.hpp @@ -9,15 +9,15 @@ struct Box { int y_min = 0; int y_max = 0; - static Box Intersection(Box a, Box b); - bool Contain(int x, int y); + static auto Intersection(Box a, Box b) -> Box; + bool Contain(int x, int y) const; bool operator==(const Box& other) const; bool operator!=(const Box& other) const; }; } // namespace ftxui -#endif /* end of include guard: FTXUI_SCREEN_BOX_HPP */ +#endif // FTXUI_SCREEN_BOX_HPP // Copyright 2020 Arthur Sonzogni. All rights reserved. // Use of this source code is governed by the MIT license that can be found in diff --git a/include/ftxui/screen/color.hpp b/include/ftxui/screen/color.hpp index dbf32ffb6..d7d789a24 100644 --- a/include/ftxui/screen/color.hpp +++ b/include/ftxui/screen/color.hpp @@ -1,8 +1,8 @@ -#ifndef FTXUI_SCREEN_COLOR -#define FTXUI_SCREEN_COLOR +#ifndef FTXUI_SCREEN_COLOR_HPP +#define FTXUI_SCREEN_COLOR_HPP -#include // for uint8_t -#include // for wstring +#include // for uint8_t +#include // for wstring #ifdef RGB // Workaround for wingdi.h (via Windows.h) defining macros that break things. @@ -313,12 +313,8 @@ class Color { Palette256, TrueColor, }; - - ColorType type_; - union { - uint8_t index_ = 0; - uint8_t red_; - }; + ColorType type_ = ColorType::Palette1; + uint8_t red_ = 0; uint8_t green_ = 0; uint8_t blue_ = 0; }; @@ -333,7 +329,7 @@ Color operator""_rgb(unsigned long long int combined); } // namespace ftxui -#endif /* end of include guard: FTXUI_COLOR_H_ */ +#endif // FTXUI_SCREEN_COLOR_HPP // Copyright 2020 Arthur Sonzogni. All rights reserved. // Use of this source code is governed by the MIT license that can be found in diff --git a/include/ftxui/screen/color_info.hpp b/include/ftxui/screen/color_info.hpp index 5a35fc5bf..2cf9e4fbd 100644 --- a/include/ftxui/screen/color_info.hpp +++ b/include/ftxui/screen/color_info.hpp @@ -1,7 +1,7 @@ #ifndef FTXUI_SCREEN_COLOR_INFO_HPP #define FTXUI_SCREEN_COLOR_INFO_HPP -#include +#include #include namespace ftxui { @@ -23,7 +23,7 @@ ColorInfo GetColorInfo(Color::Palette16 index); } // namespace ftxui -#endif /* end of include guard: FTXUI_SCREEN_COLOR_INFO_HPP */ +#endif // FTXUI_SCREEN_COLOR_INFO_HPP // Copyright 2020 Arthur Sonzogni. All rights reserved. // Use of this source code is governed by the MIT license that can be found in diff --git a/include/ftxui/screen/deprecated.hpp b/include/ftxui/screen/deprecated.hpp index 1b99d17db..0d0feacc8 100644 --- a/include/ftxui/screen/deprecated.hpp +++ b/include/ftxui/screen/deprecated.hpp @@ -8,7 +8,7 @@ int wchar_width(wchar_t); int wstring_width(const std::wstring&); } // namespace ftxui -#endif /* end of include guard: FTXUI_SCREEN_DEPRECATED_HPP */ +#endif // FTXUI_SCREEN_DEPRECATED_HPP // Copyright 2021 Arthur Sonzogni. All rights reserved. // Use of this source code is governed by the MIT license that can be found in diff --git a/include/ftxui/screen/screen.hpp b/include/ftxui/screen/screen.hpp index 45d8c14a7..21eb37764 100644 --- a/include/ftxui/screen/screen.hpp +++ b/include/ftxui/screen/screen.hpp @@ -1,5 +1,5 @@ -#ifndef FTXUI_SCREEN_SCREEN -#define FTXUI_SCREEN_SCREEN +#ifndef FTXUI_SCREEN_SCREEN_HPP +#define FTXUI_SCREEN_SCREEN_HPP #include #include // for string, allocator, basic_string @@ -14,6 +14,8 @@ namespace ftxui { /// @brief A unicode character and its associated style. /// @ingroup screen struct Pixel { + bool operator==(const Pixel& other) const; + // The graphemes stored into the pixel. To support combining characters, // like: a⃦, this can potentially contains multiple codepoitns. std::string character = " "; @@ -68,13 +70,12 @@ class Screen { int dimy() const { return dimy_; } // Move the terminal cursor n-lines up with n = dimy(). - std::string ResetPosition(bool clear = false); + std::string ResetPosition(bool clear = false) const; // Fill with space. void Clear(); void ApplyShader(); - Box stencil; struct Cursor { int x = 0; @@ -83,16 +84,20 @@ class Screen { Cursor cursor() const { return cursor_; } void SetCursor(Cursor cursor) { cursor_ = cursor; } + Box stencil; + protected: int dimx_; int dimy_; std::vector> pixels_; Cursor cursor_; + + private: }; } // namespace ftxui -#endif /* end of include guard: FTXUI_SCREEN_SCREEN */ +#endif // FTXUI_SCREEN_SCREEN_HPP // Copyright 2020 Arthur Sonzogni. All rights reserved. // Use of this source code is governed by the MIT license that can be found in diff --git a/include/ftxui/screen/terminal.hpp b/include/ftxui/screen/terminal.hpp index 9a6b6e616..91574d885 100644 --- a/include/ftxui/screen/terminal.hpp +++ b/include/ftxui/screen/terminal.hpp @@ -1,5 +1,5 @@ -#ifndef FTXUI_CORE_TERMINAL_HPP -#define FTXUI_CORE_TERMINAL_HPP +#ifndef FTXUI_SCREEN_TERMINAL_HPP +#define FTXUI_SCREEN_TERMINAL_HPP namespace ftxui { struct Dimensions { @@ -22,7 +22,7 @@ Color ColorSupport(); } // namespace ftxui -#endif /* end of include guard: FTXUI_CORE_TERMINAL_HPP */ +#endif // FTXUI_SCREEN_TERMINAL_HPP // Copyright 2020 Arthur Sonzogni. All rights reserved. // Use of this source code is governed by the MIT license that can be found in diff --git a/src/ftxui/component/animation.cpp b/src/ftxui/component/animation.cpp index 1c7da934b..49cc3cd08 100644 --- a/src/ftxui/component/animation.cpp +++ b/src/ftxui/component/animation.cpp @@ -1,14 +1,18 @@ -#define _USE_MATH_DEFINES -#include // for sin, pow, sqrt, M_PI_2, M_PI, cos +#include +#include // for ratio +#include // for move #include "ftxui/component/animation.hpp" -#include // for ratio - -namespace ftxui { -namespace animation { +namespace ftxui::animation { namespace easing { + +namespace { +constexpr float kPi = 3.14159265358979323846F; +constexpr float kPi2 = kPi / 2.F; +} // namespace + // Easing function have been taken out of: // https://github.com/warrenm/AHEasing/blob/master/AHEasing/easing.c // @@ -40,7 +44,7 @@ float QuadraticOut(float p) { // y = (1/2)((2x)^2) ; [0, 0.5) // y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1] float QuadraticInOut(float p) { - if (p < 0.5) { + if (p < 0.5F) { // NOLINT return 2 * p * p; } else { return (-2 * p * p) + (4 * p) - 1; @@ -62,11 +66,11 @@ float CubicOut(float p) { // y = (1/2)((2x)^3) ; [0, 0.5) // y = (1/2)((2x-2)^3 + 2) ; [0.5, 1] float CubicInOut(float p) { - if (p < 0.5) { + if (p < 0.5F) { // NOLINT return 4 * p * p * p; } else { float f = ((2 * p) - 2); - return 0.5 * f * f * f + 1; + return 0.5F * f * f * f + 1; // NOLINT } } @@ -85,11 +89,11 @@ float QuarticOut(float p) { // y = (1/2)((2x)^4) ; [0, 0.5) // y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1] float QuarticInOut(float p) { - if (p < 0.5) { - return 8 * p * p * p * p; + if (p < 0.5F) { // NOLINT + return 8 * p * p * p * p; // NOLINT } else { float f = (p - 1); - return -8 * f * f * f * f + 1; + return -8 * f * f * f * f + 1; // NOLINT } } @@ -108,119 +112,122 @@ float QuinticOut(float p) { // y = (1/2)((2x)^5) ; [0, 0.5) // y = (1/2)((2x-2)^5 + 2) ; [0.5, 1] float QuinticInOut(float p) { - if (p < 0.5) { - return 16 * p * p * p * p * p; - } else { - float f = ((2 * p) - 2); - return 0.5 * f * f * f * f * f + 1; + if (p < 0.5F) { // NOLINT + return 16 * p * p * p * p * p; // NOLINT + } else { // NOLINT + float f = ((2 * p) - 2); // NOLINT + return 0.5 * f * f * f * f * f + 1; // NOLINT } } // Modeled after quarter-cycle of sine wave float SineIn(float p) { - return sin((p - 1) * M_PI_2) + 1; + return std::sin((p - 1) * kPi2) + 1; } // Modeled after quarter-cycle of sine wave (different phase) float SineOut(float p) { - return sin(p * M_PI_2); + return std::sin(p * kPi2); } // Modeled after half sine wave float SineInOut(float p) { - return 0.5 * (1 - cos(p * M_PI)); + return 0.5F * (1 - std::cos(p * kPi)); // NOLINT } // Modeled after shifted quadrant IV of unit circle float CircularIn(float p) { - return 1 - sqrt(1 - (p * p)); + return 1 - std::sqrt(1 - (p * p)); } // Modeled after shifted quadrant II of unit circle float CircularOut(float p) { - return sqrt((2 - p) * p); + return std::sqrt((2 - p) * p); } // Modeled after the piecewise circular function // y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5) // y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1] float CircularInOut(float p) { - if (p < 0.5) { - return 0.5 * (1 - sqrt(1 - 4 * (p * p))); + if (p < 0.5F) { // NOLINT + return 0.5F * (1 - std::sqrt(1 - 4 * (p * p))); // NOLINT } else { - return 0.5 * (sqrt(-((2 * p) - 3) * ((2 * p) - 1)) + 1); + return 0.5F * (std::sqrt(-((2 * p) - 3) * ((2 * p) - 1)) + 1); // NOLINT } } // Modeled after the exponential function y = 2^(10(x - 1)) float ExponentialIn(float p) { - return (p == 0.0) ? p : pow(2, 10 * (p - 1)); + return (p == 0.0) ? p : std::pow(2, 10 * (p - 1)); // NOLINT } // Modeled after the exponential function y = -2^(-10x) + 1 float ExponentialOut(float p) { - return (p == 1.0) ? p : 1 - pow(2, -10 * p); + return (p == 1.0) ? p : 1 - std::pow(2, -10 * p); // NOLINT } // Modeled after the piecewise exponential // y = (1/2)2^(10(2x - 1)) ; [0,0.5) // y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1] float ExponentialInOut(float p) { - if (p == 0.0 || p == 1.0) + if (p == 0.0 || p == 1.F) { return p; + } - if (p < 0.5) { - return 0.5 * pow(2, (20 * p) - 10); - } else { - return -0.5 * pow(2, (-20 * p) + 10) + 1; + if (p < 0.5F) { // NOLINT + return 0.5 * std::pow(2, (20 * p) - 10); // NOLINT + } else { // NOLINT + return -0.5 * std::pow(2, (-20 * p) + 10) + 1; // NOLINT } } // Modeled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1)) float ElasticIn(float p) { - return sin(13 * M_PI_2 * p) * pow(2, 10 * (p - 1)); + return std::sin(13.F * kPi2 * p) * std::pow(2.F, 10.F * (p - 1)); // NOLINT } // Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + // 1 float ElasticOut(float p) { - return sin(-13 * M_PI_2 * (p + 1)) * pow(2, -10 * p) + 1; + return std::sin(-13.F * kPi2 * (p + 1)) * std::pow(2.F, -10.F * p) + + 1; // NOLINT } // Modeled after the piecewise exponentially-damped sine wave: // y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5) // y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1] float ElasticInOut(float p) { - if (p < 0.5) { - return 0.5 * sin(13 * M_PI_2 * (2 * p)) * pow(2, 10 * ((2 * p) - 1)); - } else { - return 0.5 * - (sin(-13 * M_PI_2 * ((2 * p - 1) + 1)) * pow(2, -10 * (2 * p - 1)) + - 2); + if (p < 0.5F) { // NOLINT + return 0.5 * std::sin(13.F * kPi2 * (2 * p)) * // NOLINT + std::pow(2, 10 * ((2 * p) - 1)); // NOLINT + } else { // NOLINT + return 0.5 * (std::sin(-13.F * kPi2 * ((2 * p - 1) + 1)) * // NOLINT + std::pow(2, -10 * (2 * p - 1)) + // NOLINT + 2); // NOLINT } } // Modeled after the overshooting cubic y = x^3-x*sin(x*pi) float BackIn(float p) { - return p * p * p - p * sin(p * M_PI); + return p * p * p - p * std::sin(p * kPi); } // Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi)) float BackOut(float p) { float f = (1 - p); - return 1 - (f * f * f - f * sin(f * M_PI)); + return 1 - (f * f * f - f * std::sin(f * kPi)); } // Modeled after the piecewise overshooting cubic function: // y = (1/2)*((2x)^3-(2x)*sin(2*x*pi)) ; [0, 0.5) // y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1] float BackInOut(float p) { - if (p < 0.5) { + if (p < 0.5F) { // NOLINT float f = 2 * p; - return 0.5 * (f * f * f - f * sin(f * M_PI)); + return 0.5F * (f * f * f - f * std::sin(f * kPi)); // NOLINT } else { - float f = (1 - (2 * p - 1)); - return 0.5 * (1 - (f * f * f - f * sin(f * M_PI))) + 0.5; + float f = (1 - (2 * p - 1)); // NOLINT + return 0.5F * (1 - (f * f * f - f * std::sin(f * kPi))) + 0.5; // NOLINT } } @@ -229,22 +236,23 @@ float BounceIn(float p) { } float BounceOut(float p) { - if (p < 4 / 11.0) { - return (121 * p * p) / 16.0; - } else if (p < 8 / 11.0) { - return (363 / 40.0 * p * p) - (99 / 10.0 * p) + 17 / 5.0; - } else if (p < 9 / 10.0) { - return (4356 / 361.0 * p * p) - (35442 / 1805.0 * p) + 16061 / 1805.0; - } else { - return (54 / 5.0 * p * p) - (513 / 25.0 * p) + 268 / 25.0; + if (p < 4 / 11.0) { // NOLINT + return (121 * p * p) / 16.0; // NOLINT + } else if (p < 8 / 11.0) { // NOLINT + return (363 / 40.0 * p * p) - (99 / 10.0 * p) + 17 / 5.0; // NOLINT + } else if (p < 9 / 10.0) { // NOLINT + return (4356 / 361.0 * p * p) - (35442 / 1805.0 * p) + // NOLINT + 16061 / 1805.0; // NOLINT + } else { // NOLINT + return (54 / 5.0 * p * p) - (513 / 25.0 * p) + 268 / 25.0; // NOLINT } } -float BounceInOut(float p) { - if (p < 0.5) { - return 0.5 * BounceIn(p * 2); - } else { - return 0.5 * BounceOut(p * 2 - 1) + 0.5; +float BounceInOut(float p) { // NOLINT + if (p < 0.5F) { // NOLINT + return 0.5F * BounceIn(p * 2); // NOLINT + } else { // NOLINT + return 0.5F * BounceOut(p * 2 - 1) + 0.5F; // NOLINT } } @@ -259,7 +267,7 @@ Animator::Animator(float* from, from_(*from), to_(to), duration_(duration), - easing_function_(easing_function), + easing_function_(std::move(easing_function)), current_(-delay) { RequestAnimationFrame(); } @@ -275,11 +283,11 @@ void Animator::OnAnimation(Params& params) { if (current_ <= Duration()) { *value_ = from_; } else { - *value_ = from_ + (to_ - from_) * easing_function_(current_ / duration_); + *value_ = from_ + + (to_ - from_) * easing_function_(current_ / duration_); // NOLINT } RequestAnimationFrame(); } -} // namespace animation -} // namespace ftxui +} // namespace ftxui::animation diff --git a/src/ftxui/component/button.cpp b/src/ftxui/component/button.cpp index 9222883ef..b827f2db6 100644 --- a/src/ftxui/component/button.cpp +++ b/src/ftxui/component/button.cpp @@ -1,17 +1,16 @@ #include // for function #include // for shared_ptr -#include // for string #include // for move #include "ftxui/component/animation.hpp" // for Animator, Params (ptr only) #include "ftxui/component/captured_mouse.hpp" // for CapturedMouse #include "ftxui/component/component.hpp" // for Make, Button #include "ftxui/component/component_base.hpp" // for ComponentBase -#include "ftxui/component/component_options.hpp" // for ButtonOption, AnimatedColorOption, AnimatedColorsOption +#include "ftxui/component/component_options.hpp" // for ButtonOption, AnimatedColorOption, AnimatedColorsOption, EntryState #include "ftxui/component/event.hpp" // for Event, Event::Return #include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed #include "ftxui/component/screen_interactive.hpp" // for Component -#include "ftxui/dom/elements.hpp" // for operator|, Decorator, Element, bgcolor, color, operator|=, reflect, text, border, inverted, nothing +#include "ftxui/dom/elements.hpp" // for operator|, Decorator, Element, operator|=, bgcolor, color, reflect, text, bold, border, inverted, nothing #include "ftxui/screen/box.hpp" // for Box #include "ftxui/screen/color.hpp" // for Color #include "ftxui/util/ref.hpp" // for Ref, ConstStringRef @@ -20,12 +19,14 @@ namespace ftxui { namespace { -Element DefaultTransform(EntryState params) { +Element DefaultTransform(EntryState params) { // NOLINT auto element = text(params.label) | border; - if (params.active) + if (params.active) { element |= bold; - if (params.focused) + } + if (params.focused) { element |= inverted; + } return element; } @@ -62,13 +63,16 @@ Component Button(ConstStringRef label, Impl(ConstStringRef label, std::function on_click, Ref option) - : label_(label), on_click_(on_click), option_(std::move(option)) {} + : label_(std::move(label)), + on_click_(std::move(on_click)), + option_(std::move(option)) {} // Component implementation: Element Render() override { - float target = Focused() ? 1.0 : 0.f; - if (target != animator_background_.to()) + float target = Focused() ? 1.F : 0.F; // NOLINT + if (target != animator_background_.to()) { SetAnimationTarget(target); + } EntryState state = { *label_, @@ -122,14 +126,15 @@ Component Button(ConstStringRef label, void OnClick() { on_click_(); - animation_background_ = 0.5f; - animation_foreground_ = 0.5f; - SetAnimationTarget(1.f); + animation_background_ = 0.5F; // NOLINT + animation_foreground_ = 0.5F; // NOLINT + SetAnimationTarget(1.F); // NOLINT } bool OnEvent(Event event) override { - if (event.is_mouse()) + if (event.is_mouse()) { return OnMouseEvent(event); + } if (event == Event::Return) { OnClick(); @@ -142,8 +147,9 @@ Component Button(ConstStringRef label, mouse_hover_ = box_.Contain(event.mouse().x, event.mouse().y) && CaptureMouse(event); - if (!mouse_hover_) + if (!mouse_hover_) { return false; + } TakeFocus(); @@ -172,7 +178,7 @@ Component Button(ConstStringRef label, animation::Animator(&animation_foreground_); }; - return Make(label, std::move(on_click), std::move(option)); + return Make(std::move(label), std::move(on_click), std::move(option)); } } // namespace ftxui diff --git a/src/ftxui/component/catch_event.cpp b/src/ftxui/component/catch_event.cpp index 0ea0ec6d8..8a83f4730 100644 --- a/src/ftxui/component/catch_event.cpp +++ b/src/ftxui/component/catch_event.cpp @@ -11,15 +11,16 @@ namespace ftxui { class CatchEventBase : public ComponentBase { public: // Constructor. - CatchEventBase(std::function on_event) + explicit CatchEventBase(std::function on_event) : on_event_(std::move(on_event)) {} // Component implementation. bool OnEvent(Event event) override { - if (on_event_(event)) + if (on_event_(event)) { return true; - else + } else { return ComponentBase::OnEvent(event); + } } protected: @@ -76,8 +77,8 @@ Component CatchEvent(Component child, /// ``` ComponentDecorator CatchEvent(std::function on_event) { return [on_event = std::move(on_event)](Component child) { - return CatchEvent(child, [on_event = std::move(on_event)](Event event) { - return on_event(event); + return CatchEvent(std::move(child), [on_event = on_event](Event event) { + return on_event(std::move(event)); }); }; } diff --git a/src/ftxui/component/checkbox.cpp b/src/ftxui/component/checkbox.cpp index 12d8cae76..9e7c35413 100644 --- a/src/ftxui/component/checkbox.cpp +++ b/src/ftxui/component/checkbox.cpp @@ -18,7 +18,7 @@ namespace { class CheckboxBase : public ComponentBase { public: CheckboxBase(ConstStringRef label, bool* state, Ref option) - : label_(label), state_(state), option_(std::move(option)) {} + : label_(std::move(label)), state_(state), option_(std::move(option)) {} private: // Component implementation. @@ -32,18 +32,20 @@ class CheckboxBase : public ComponentBase { is_active, is_focused || hovered_, }; - auto element = (option_->transform - ? option_->transform - : CheckboxOption::Simple().transform)(std::move(state)); + auto element = + (option_->transform ? option_->transform + : CheckboxOption::Simple().transform)(state); return element | focus_management | reflect(box_); } bool OnEvent(Event event) override { - if (!CaptureMouse(event)) + if (!CaptureMouse(event)) { return false; + } - if (event.is_mouse()) + if (event.is_mouse()) { return OnMouseEvent(event); + } hovered_ = false; if (event == Event::Character(' ') || event == Event::Return) { @@ -58,11 +60,13 @@ class CheckboxBase : public ComponentBase { bool OnMouseEvent(Event event) { hovered_ = box_.Contain(event.mouse().x, event.mouse().y); - if (!CaptureMouse(event)) + if (!CaptureMouse(event)) { return false; + } - if (!hovered_) + if (!hovered_) { return false; + } if (event.mouse().button == Mouse::Left && event.mouse().motion == Mouse::Pressed) { @@ -109,7 +113,7 @@ class CheckboxBase : public ComponentBase { Component Checkbox(ConstStringRef label, bool* checked, Ref option) { - return Make(label, checked, std::move(option)); + return Make(std::move(label), checked, std::move(option)); } } // namespace ftxui diff --git a/src/ftxui/component/collapsible.cpp b/src/ftxui/component/collapsible.cpp index ad4b159a5..884b2c4bf 100644 --- a/src/ftxui/component/collapsible.cpp +++ b/src/ftxui/component/collapsible.cpp @@ -1,10 +1,12 @@ -#include // for string -#include // for move +#include // for function +#include // for shared_ptr, allocator +#include // for move #include "ftxui/component/component.hpp" // for Checkbox, Maybe, Make, Vertical, Collapsible #include "ftxui/component/component_base.hpp" // for Component, ComponentBase -#include "ftxui/component/component_options.hpp" // for CheckboxOption -#include "ftxui/util/ref.hpp" // for Ref, ConstStringRef +#include "ftxui/component/component_options.hpp" // for CheckboxOption, EntryState +#include "ftxui/dom/elements.hpp" // for operator|=, text, hbox, Element, bold, inverted +#include "ftxui/util/ref.hpp" // for Ref, ConstStringRef namespace ftxui { @@ -28,27 +30,28 @@ namespace ftxui { Component Collapsible(ConstStringRef label, Component child, Ref show) { class Impl : public ComponentBase { public: - Impl(ConstStringRef label, Component child, Ref show) - : show_(std::move(show)) { + Impl(ConstStringRef label, Component child, Ref show) : show_(show) { CheckboxOption opt; - opt.transform = [](EntryState s) { - auto prefix = text(s.state ? "▼ " : "▶ "); + opt.transform = [](EntryState s) { // NOLINT + auto prefix = text(s.state ? "▼ " : "▶ "); // NOLINT auto t = text(s.label); - if (s.active) + if (s.active) { t |= bold; - if (s.focused) + } + if (s.focused) { t |= inverted; + } return hbox({prefix, t}); }; Add(Container::Vertical({ - Checkbox(label, show_.operator->(), opt), + Checkbox(std::move(label), show_.operator->(), opt), Maybe(std::move(child), show_.operator->()), })); } Ref show_; }; - return Make(label, std::move(child), std::move(show)); + return Make(std::move(label), std::move(child), show); } } // namespace ftxui diff --git a/src/ftxui/component/component.cpp b/src/ftxui/component/component.cpp index e75997980..ba2cf6e34 100644 --- a/src/ftxui/component/component.cpp +++ b/src/ftxui/component/component.cpp @@ -1,6 +1,6 @@ -#include // for size_t #include // for find_if #include // for assert +#include // for size_t #include // for begin, end #include // for move #include // for vector, __alloc_traits<>::value_type @@ -37,7 +37,7 @@ ComponentBase* ComponentBase::Parent() const { /// @brief Access the child at index `i`. /// @ingroup component Component& ComponentBase::ChildAt(size_t i) { - assert(i < ChildCount()); + assert(i < ChildCount()); // NOLINT return children_[i]; } @@ -61,8 +61,9 @@ void ComponentBase::Add(Component child) { /// @see Parent /// @ingroup component void ComponentBase::Detach() { - if (!parent_) + if (parent_ == nullptr) { return; + } auto it = std::find_if(std::begin(parent_->children_), // std::end(parent_->children_), // [this](const Component& that) { // @@ -76,8 +77,9 @@ void ComponentBase::Detach() { /// @brief Remove all children. /// @ingroup component void ComponentBase::DetachAllChildren() { - while (!children_.empty()) + while (!children_.empty()) { children_[0]->Detach(); + } } /// @brief Draw the component. @@ -85,8 +87,9 @@ void ComponentBase::DetachAllChildren() { /// ftxui::ComponentBase. /// @ingroup component Element ComponentBase::Render() { - if (children_.size() == 1) + if (children_.size() == 1) { return children_.front()->Render(); + } return text("Not implemented component"); } @@ -97,10 +100,11 @@ Element ComponentBase::Render() { /// The default implementation called OnEvent on every child until one return /// true. If none returns true, return false. /// @ingroup component -bool ComponentBase::OnEvent(Event event) { - for (Component& child : children_) { - if (child->OnEvent(event)) +bool ComponentBase::OnEvent(Event event) { // NOLINT + for (Component& child : children_) { // NOLINT + if (child->OnEvent(event)) { return true; + } } return false; } @@ -110,8 +114,9 @@ bool ComponentBase::OnEvent(Event event) { /// The default implementation dispatch the event to every child. /// @ingroup component void ComponentBase::OnAnimation(animation::Params& params) { - for (Component& child : children_) + for (Component& child : children_) { child->OnAnimation(params); + } } /// @brief Return the currently Active child. @@ -119,8 +124,9 @@ void ComponentBase::OnAnimation(animation::Params& params) { /// @ingroup component Component ComponentBase::ActiveChild() { for (auto& child : children_) { - if (child->Focusable()) + if (child->Focusable()) { return child; + } } return nullptr; } @@ -130,9 +136,10 @@ Component ComponentBase::ActiveChild() { /// keyboard. /// @ingroup component bool ComponentBase::Focusable() const { - for (const Component& child : children_) { - if (child->Focusable()) + for (const Component& child : children_) { // NOLINT + if (child->Focusable()) { return true; + } } return false; } @@ -140,7 +147,7 @@ bool ComponentBase::Focusable() const { /// @brief Returns if the element if the currently active child of its parent. /// @ingroup component bool ComponentBase::Active() const { - return !parent_ || parent_->ActiveChild().get() == this; + return parent_ == nullptr || parent_->ActiveChild().get() == this; } /// @brief Returns if the elements if focused by the user. @@ -149,7 +156,7 @@ bool ComponentBase::Active() const { /// Focusable(). /// @ingroup component bool ComponentBase::Focused() const { - auto current = this; + const auto* current = this; while (current && current->Active()) { current = current->parent_; } @@ -159,12 +166,12 @@ bool ComponentBase::Focused() const { /// @brief Make the |child| to be the "active" one. /// @param child the child to become active. /// @ingroup component -void ComponentBase::SetActiveChild(ComponentBase*) {} +void ComponentBase::SetActiveChild(ComponentBase* /*child*/) {} /// @brief Make the |child| to be the "active" one. /// @param child the child to become active. /// @ingroup component -void ComponentBase::SetActiveChild(Component child) { +void ComponentBase::SetActiveChild(Component child) { // NOLINT SetActiveChild(child.get()); } @@ -182,9 +189,10 @@ void ComponentBase::TakeFocus() { /// them. It represents a component taking priority over others. /// @param event /// @ingroup component -CapturedMouse ComponentBase::CaptureMouse(const Event& event) { - if (event.screen_) +CapturedMouse ComponentBase::CaptureMouse(const Event& event) { // NOLINT + if (event.screen_) { return event.screen_->CaptureMouse(); + } return std::make_unique(); } diff --git a/src/ftxui/component/component_options.cpp b/src/ftxui/component/component_options.cpp index 029dcd207..508ebdf7a 100644 --- a/src/ftxui/component/component_options.cpp +++ b/src/ftxui/component/component_options.cpp @@ -1,9 +1,10 @@ #include "ftxui/component/component_options.hpp" -#include // for allocator, shared_ptr +#include // for shared_ptr +#include // for move #include "ftxui/component/animation.hpp" // for Function, Duration -#include "ftxui/dom/elements.hpp" // for Element, operator|, text, bold, dim, inverted, automerge +#include "ftxui/dom/elements.hpp" // for operator|=, text, Element, bold, inverted, operator|, dim, hbox, automerge, borderEmpty, borderLight namespace ftxui { @@ -15,13 +16,13 @@ void AnimatedColorOption::Set(Color a_inactive, inactive = a_inactive; active = a_active; duration = a_duration; - function = a_function; + function = std::move(a_function); } void UnderlineOption::SetAnimation(animation::Duration d, animation::easing::Function f) { SetAnimationDuration(d); - SetAnimationFunction(f); + SetAnimationFunction(std::move(f)); } void UnderlineOption::SetAnimationDuration(animation::Duration d) { @@ -31,28 +32,31 @@ void UnderlineOption::SetAnimationDuration(animation::Duration d) { void UnderlineOption::SetAnimationFunction(animation::easing::Function f) { leader_function = f; - follower_function = f; + follower_function = std::move(f); } void UnderlineOption::SetAnimationFunction( animation::easing::Function f_leader, animation::easing::Function f_follower) { - leader_function = f_leader; - follower_function = f_follower; + leader_function = std::move(f_leader); + follower_function = std::move(f_follower); } // static MenuOption MenuOption::Horizontal() { MenuOption option; option.direction = Direction::Right; - option.entries.transform = [](EntryState state) { + option.entries.transform = [](const EntryState& state) { Element e = text(state.label); - if (state.focused) + if (state.focused) { e |= inverted; - if (state.active) + } + if (state.active) { e |= bold; - if (!state.focused && !state.active) + } + if (!state.focused && !state.active) { e |= dim; + } return e; }; option.elements_infix = [] { return text(" "); }; @@ -70,19 +74,17 @@ MenuOption MenuOption::HorizontalAnimated() { // static MenuOption MenuOption::Vertical() { MenuOption option; - option.entries.transform = [](EntryState state) { - if (state.active) - state.label = "> " + state.label; - else - state.label = " " + state.label; - - Element e = text(state.label); - if (state.focused) + option.entries.transform = [](const EntryState& state) { + Element e = text((state.active ? "> " : " ") + state.label); // NOLINT + if (state.focused) { e |= inverted; - if (state.active) + } + if (state.active) { e |= bold; - if (!state.focused && !state.active) + } + if (!state.focused && !state.active) { e |= dim; + } return e; }; return option; @@ -91,14 +93,17 @@ MenuOption MenuOption::Vertical() { // static MenuOption MenuOption::VerticalAnimated() { auto option = MenuOption::Vertical(); - option.entries.transform = [](EntryState state) { + option.entries.transform = [](const EntryState& state) { Element e = text(state.label); - if (state.focused) + if (state.focused) { e |= inverted; - if (state.active) + } + if (state.active) { e |= bold; - if (!state.focused && !state.active) + } + if (!state.focused && !state.active) { e |= dim; + } return e; }; option.underline.enabled = true; @@ -116,10 +121,10 @@ MenuOption MenuOption::Toggle() { // static ButtonOption ButtonOption::Ascii() { ButtonOption option; - option.transform = [](EntryState s) { - s.label = s.focused ? "[" + s.label + "]" // - : " " + s.label + " "; - return text(s.label); + option.transform = [](const EntryState& s) { + std::string label = s.focused ? "[" + s.label + "]" // + : " " + s.label + " "; + return text(label); }; return option; } @@ -128,10 +133,11 @@ ButtonOption ButtonOption::Ascii() { // static ButtonOption ButtonOption::Simple() { ButtonOption option; - option.transform = [](EntryState s) { + option.transform = [](const EntryState& s) { auto element = text(s.label) | borderLight; - if (s.focused) + if (s.focused) { element |= inverted; + } return element; }; return option; @@ -147,10 +153,11 @@ ButtonOption ButtonOption::Animated() { /// @brief Create a ButtonOption, using animated colors. // static ButtonOption ButtonOption::Animated(Color color) { - return ButtonOption::Animated(Color::Interpolate(0.85f, color, Color::Black), - Color::Interpolate(0.10f, color, Color::White), - Color::Interpolate(0.10f, color, Color::Black), - Color::Interpolate(0.85f, color, Color::White)); + return ButtonOption::Animated( + Color::Interpolate(0.85F, color, Color::Black), // NOLINT + Color::Interpolate(0.10F, color, Color::White), // NOLINT + Color::Interpolate(0.10F, color, Color::Black), // NOLINT + Color::Interpolate(0.85F, color, Color::White)); // NOLINT } /// @brief Create a ButtonOption, using animated colors. @@ -163,17 +170,18 @@ ButtonOption ButtonOption::Animated(Color background, Color foreground) { // static ButtonOption ButtonOption::Animated(Color background, Color foreground, - Color background_focused, - Color foreground_focused) { + Color background_active, + Color foreground_active) { ButtonOption option; - option.transform = [](EntryState s) { + option.transform = [](const EntryState& s) { auto element = text(s.label) | borderEmpty; - if (s.focused) + if (s.focused) { element |= bold; + } return element; }; - option.animated_colors.foreground.Set(foreground, foreground_focused); - option.animated_colors.background.Set(background, background_focused); + option.animated_colors.foreground.Set(foreground, foreground_active); + option.animated_colors.background.Set(background, background_active); return option; } @@ -181,19 +189,21 @@ ButtonOption ButtonOption::Animated(Color background, // static CheckboxOption CheckboxOption::Simple() { auto option = CheckboxOption(); - option.transform = [](EntryState s) { + option.transform = [](const EntryState& s) { #if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK) // Microsoft terminal do not use fonts able to render properly the default // radiobox glyph. - auto prefix = text(s.state ? "[X] " : "[ ] "); + auto prefix = text(s.state ? "[X] " : "[ ] "); // NOLINT #else - auto prefix = text(s.state ? "▣ " : "☐ "); + auto prefix = text(s.state ? "▣ " : "☐ "); // NOLINT #endif auto t = text(s.label); - if (s.active) + if (s.active) { t |= bold; - if (s.focused) + } + if (s.focused) { t |= inverted; + } return hbox({prefix, t}); }; return option; @@ -203,19 +213,21 @@ CheckboxOption CheckboxOption::Simple() { // static RadioboxOption RadioboxOption::Simple() { auto option = RadioboxOption(); - option.transform = [](EntryState s) { + option.transform = [](const EntryState& s) { #if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK) // Microsoft terminal do not use fonts able to render properly the default // radiobox glyph. - auto prefix = text(s.state ? "(*) " : "( ) "); + auto prefix = text(s.state ? "(*) " : "( ) "); // NOLINT #else - auto prefix = text(s.state ? "◉ " : "○ "); + auto prefix = text(s.state ? "◉ " : "○ "); // NOLINT #endif auto t = text(s.label); - if (s.active) + if (s.active) { t |= bold; - if (s.focused) + } + if (s.focused) { t |= inverted; + } return hbox({prefix, t}); }; return option; diff --git a/src/ftxui/component/container.cpp b/src/ftxui/component/container.cpp index 246d45659..51224e3dc 100644 --- a/src/ftxui/component/container.cpp +++ b/src/ftxui/component/container.cpp @@ -1,5 +1,5 @@ -#include // for size_t #include // for max, min +#include // for size_t #include // for make_shared, __shared_ptr_access, allocator, shared_ptr, allocator_traits<>::value_type #include // for move #include // for vector, __alloc_traits<>::value_type @@ -17,27 +17,32 @@ class ContainerBase : public ComponentBase { public: ContainerBase(Components children, int* selector) : selector_(selector ? selector : &selected_) { - for (Component& child : children) + for (Component& child : children) { Add(std::move(child)); + } } // Component override. bool OnEvent(Event event) override { - if (event.is_mouse()) + if (event.is_mouse()) { return OnMouseEvent(event); + } - if (!Focused()) + if (!Focused()) { return false; + } - if (ActiveChild() && ActiveChild()->OnEvent(event)) + if (ActiveChild() && ActiveChild()->OnEvent(event)) { return true; + } return EventHandler(event); } Component ActiveChild() override { - if (children_.size() == 0) + if (children_.empty()) { return nullptr; + } return children_[*selector_ % children_.size()]; } @@ -45,7 +50,7 @@ class ContainerBase : public ComponentBase { void SetActiveChild(ComponentBase* child) override { for (size_t i = 0; i < children_.size(); ++i) { if (children_[i].get() == child) { - *selector_ = i; + *selector_ = (int)i; return; } } @@ -53,10 +58,10 @@ class ContainerBase : public ComponentBase { protected: // Handlers - virtual bool EventHandler(Event) { return false; } + virtual bool EventHandler(Event /*unused*/) { return false; } // NOLINT virtual bool OnMouseEvent(Event event) { - return ComponentBase::OnEvent(event); + return ComponentBase::OnEvent(std::move(event)); } int selected_ = 0; @@ -71,11 +76,16 @@ class ContainerBase : public ComponentBase { } } } + void MoveSelectorWrap(int dir) { + if (children_.empty()) { + return; + } for (size_t offset = 1; offset < children_.size(); ++offset) { - int i = (*selector_ + offset * dir + children_.size()) % children_.size(); + size_t i = ((size_t(*selector_ + offset * dir + children_.size())) % + children_.size()); if (children_[i]->Focusable()) { - *selector_ = i; + *selector_ = (int)i; return; } } @@ -88,60 +98,74 @@ class VerticalContainer : public ContainerBase { Element Render() override { Elements elements; - for (auto& it : children_) + for (auto& it : children_) { elements.push_back(it->Render()); - if (elements.size() == 0) + } + if (elements.empty()) { return text("Empty container") | reflect(box_); + } return vbox(std::move(elements)) | reflect(box_); } bool EventHandler(Event event) override { int old_selected = *selector_; - if (event == Event::ArrowUp || event == Event::Character('k')) + if (event == Event::ArrowUp || event == Event::Character('k')) { MoveSelector(-1); - if (event == Event::ArrowDown || event == Event::Character('j')) + } + if (event == Event::ArrowDown || event == Event::Character('j')) { MoveSelector(+1); + } if (event == Event::PageUp) { - for (int i = 0; i < box_.y_max - box_.y_min; ++i) + for (int i = 0; i < box_.y_max - box_.y_min; ++i) { MoveSelector(-1); + } } if (event == Event::PageDown) { - for (int i = 0; i < box_.y_max - box_.y_min; ++i) + for (int i = 0; i < box_.y_max - box_.y_min; ++i) { MoveSelector(1); + } } if (event == Event::Home) { - for (size_t i = 0; i < children_.size(); ++i) + for (size_t i = 0; i < children_.size(); ++i) { MoveSelector(-1); + } } if (event == Event::End) { - for (size_t i = 0; i < children_.size(); ++i) + for (size_t i = 0; i < children_.size(); ++i) { MoveSelector(1); + } } - if (event == Event::Tab && children_.size()) + if (event == Event::Tab) { MoveSelectorWrap(+1); - if (event == Event::TabReverse && children_.size()) + } + if (event == Event::TabReverse) { MoveSelectorWrap(-1); + } *selector_ = std::max(0, std::min(int(children_.size()) - 1, *selector_)); return old_selected != *selector_; } bool OnMouseEvent(Event event) override { - if (ContainerBase::OnMouseEvent(event)) + if (ContainerBase::OnMouseEvent(event)) { return true; + } if (event.mouse().button != Mouse::WheelUp && event.mouse().button != Mouse::WheelDown) { return false; } - if (!box_.Contain(event.mouse().x, event.mouse().y)) + if (!box_.Contain(event.mouse().x, event.mouse().y)) { return false; + } - if (event.mouse().button == Mouse::WheelUp) + if (event.mouse().button == Mouse::WheelUp) { MoveSelector(-1); - if (event.mouse().button == Mouse::WheelDown) + } + if (event.mouse().button == Mouse::WheelDown) { MoveSelector(+1); + } *selector_ = std::max(0, std::min(int(children_.size()) - 1, *selector_)); return true; @@ -156,23 +180,29 @@ class HorizontalContainer : public ContainerBase { Element Render() override { Elements elements; - for (auto& it : children_) + for (auto& it : children_) { elements.push_back(it->Render()); - if (elements.size() == 0) + } + if (elements.empty()) { return text("Empty container"); + } return hbox(std::move(elements)); } bool EventHandler(Event event) override { int old_selected = *selector_; - if (event == Event::ArrowLeft || event == Event::Character('h')) + if (event == Event::ArrowLeft || event == Event::Character('h')) { MoveSelector(-1); - if (event == Event::ArrowRight || event == Event::Character('l')) + } + if (event == Event::ArrowRight || event == Event::Character('l')) { MoveSelector(+1); - if (event == Event::Tab && children_.size()) + } + if (event == Event::Tab) { MoveSelectorWrap(+1); - if (event == Event::TabReverse && children_.size()) + } + if (event == Event::TabReverse) { MoveSelectorWrap(-1); + } *selector_ = std::max(0, std::min(int(children_.size()) - 1, *selector_)); return old_selected != *selector_; @@ -185,14 +215,16 @@ class TabContainer : public ContainerBase { Element Render() override { Component active_child = ActiveChild(); - if (active_child) + if (active_child) { return active_child->Render(); + } return text("Empty container"); } bool Focusable() const override { - if (children_.size() == 0) + if (children_.empty()) { return false; + } return children_[*selector_ % children_.size()]->Focusable(); } diff --git a/src/ftxui/component/dropdown.cpp b/src/ftxui/component/dropdown.cpp index 51abd9c3f..3faa103a2 100644 --- a/src/ftxui/component/dropdown.cpp +++ b/src/ftxui/component/dropdown.cpp @@ -1,12 +1,12 @@ -#include // for max, min -#include // for __shared_ptr_access -#include // for string -#include // for move +#include // for max, min +#include // for function +#include // for __shared_ptr_access, shared_ptr, allocator +#include // for string #include "ftxui/component/component.hpp" // for Maybe, Checkbox, Make, Radiobox, Vertical, Dropdown #include "ftxui/component/component_base.hpp" // for Component, ComponentBase -#include "ftxui/component/component_options.hpp" // for CheckboxOption -#include "ftxui/dom/elements.hpp" // for operator|, Element, border, filler, separator, size, vbox, frame, vscroll_indicator, HEIGHT, LESS_THAN +#include "ftxui/component/component_options.hpp" // for CheckboxOption, EntryState +#include "ftxui/dom/elements.hpp" // for operator|, Element, border, filler, operator|=, separator, size, text, vbox, frame, vscroll_indicator, hbox, HEIGHT, LESS_THAN, bold, inverted #include "ftxui/util/ref.hpp" // for ConstStringListRef namespace ftxui { @@ -15,15 +15,17 @@ Component Dropdown(ConstStringListRef entries, int* selected) { class Impl : public ComponentBase { public: Impl(ConstStringListRef entries, int* selected) - : entries_(std::move(entries)), selected_(selected) { + : entries_(entries), selected_(selected) { CheckboxOption option; - option.transform = [](EntryState s) { - auto prefix = text(s.state ? "↓ " : "→ "); + option.transform = [](const EntryState& s) { + auto prefix = text(s.state ? "↓ " : "→ "); // NOLINT auto t = text(s.label); - if (s.active) + if (s.active) { t |= bold; - if (s.focused) + } + if (s.focused) { t |= inverted; + } return hbox({prefix, t}); }; checkbox_ = Checkbox(&title_, &show_, option), @@ -39,11 +41,12 @@ Component Dropdown(ConstStringListRef entries, int* selected) { *selected_ = std::min((int)entries_.size() - 1, std::max(0, *selected_)); title_ = entries_[*selected_]; if (show_) { + const int max_height = 12; return vbox({ checkbox_->Render(), separator(), radiobox_->Render() | vscroll_indicator | frame | - size(HEIGHT, LESS_THAN, 12), + size(HEIGHT, LESS_THAN, max_height), }) | border; } @@ -63,7 +66,7 @@ Component Dropdown(ConstStringListRef entries, int* selected) { Component radiobox_; }; - return Make(std::move(entries), selected); + return Make(entries, selected); } } // namespace ftxui diff --git a/src/ftxui/component/event.cpp b/src/ftxui/component/event.cpp index 9c797bdf1..81a3629cf 100644 --- a/src/ftxui/component/event.cpp +++ b/src/ftxui/component/event.cpp @@ -29,7 +29,7 @@ Event Event::Mouse(std::string input, struct Mouse mouse) { Event event; event.input_ = std::move(input); event.type_ = Type::Mouse; - event.mouse_ = mouse; + event.mouse_ = mouse; // NOLINT return event; } @@ -45,40 +45,39 @@ Event Event::CursorReporting(std::string input, int x, int y) { Event event; event.input_ = std::move(input); event.type_ = Type::CursorReporting; - event.cursor_.x = x; - event.cursor_.y = y; + event.cursor_.x = x; // NOLINT + event.cursor_.y = y; // NOLINT return event; } // --- Arrow --- -const Event Event::ArrowLeft = Event::Special("\x1B[D"); -const Event Event::ArrowRight = Event::Special("\x1B[C"); -const Event Event::ArrowUp = Event::Special("\x1B[A"); -const Event Event::ArrowDown = Event::Special("\x1B[B"); -const Event Event::Backspace = Event::Special({127}); -const Event Event::Delete = Event::Special("\x1B[3~"); -const Event Event::Escape = Event::Special("\x1B"); -const Event Event::Return = Event::Special({10}); -const Event Event::Tab = Event::Special({9}); -const Event Event::TabReverse = Event::Special({27, 91, 90}); -const Event Event::F1 = Event::Special("\x1B[OP"); -const Event Event::F2 = Event::Special("\x1B[OQ"); -const Event Event::F3 = Event::Special("\x1B[OR"); -const Event Event::F4 = Event::Special("\x1B[OS"); -const Event Event::F5 = Event::Special("\x1B[15~"); -const Event Event::F6 = Event::Special("\x1B[17~"); -const Event Event::F7 = Event::Special("\x1B[18~"); -const Event Event::F8 = Event::Special("\x1B[19~"); -const Event Event::F9 = Event::Special("\x1B[20~"); -const Event Event::F10 = Event::Special("\x1B[21~"); -const Event Event::F11 = Event::Special("\x1B[21~"); // Doesn't exist -const Event Event::F12 = Event::Special("\x1B[24~"); -const Event Event::Home = Event::Special({27, 91, 72}); -const Event Event::End = Event::Special({27, 91, 70}); -const Event Event::PageUp = Event::Special({27, 91, 53, 126}); -const Event Event::PageDown = Event::Special({27, 91, 54, 126}); - -Event Event::Custom = Event::Special({0}); +const Event Event::ArrowLeft = Event::Special("\x1B[D"); // NOLINT +const Event Event::ArrowRight = Event::Special("\x1B[C"); // NOLINT +const Event Event::ArrowUp = Event::Special("\x1B[A"); // NOLINT +const Event Event::ArrowDown = Event::Special("\x1B[B"); // NOLINT +const Event Event::Backspace = Event::Special({127}); // NOLINT +const Event Event::Delete = Event::Special("\x1B[3~"); // NOLINT +const Event Event::Escape = Event::Special("\x1B"); // NOLINT +const Event Event::Return = Event::Special({10}); // NOLINT +const Event Event::Tab = Event::Special({9}); // NOLINT +const Event Event::TabReverse = Event::Special({27, 91, 90}); // NOLINT +const Event Event::F1 = Event::Special("\x1B[OP"); // NOLINT +const Event Event::F2 = Event::Special("\x1B[OQ"); // NOLINT +const Event Event::F3 = Event::Special("\x1B[OR"); // NOLINT +const Event Event::F4 = Event::Special("\x1B[OS"); // NOLINT +const Event Event::F5 = Event::Special("\x1B[15~"); // NOLINT +const Event Event::F6 = Event::Special("\x1B[17~"); // NOLINT +const Event Event::F7 = Event::Special("\x1B[18~"); // NOLINT +const Event Event::F8 = Event::Special("\x1B[19~"); // NOLINT +const Event Event::F9 = Event::Special("\x1B[20~"); // NOLINT +const Event Event::F10 = Event::Special("\x1B[21~"); // NOLINT +const Event Event::F11 = Event::Special("\x1B[21~"); // Doesn't exist // NOLINT +const Event Event::F12 = Event::Special("\x1B[24~"); // NOLINT +const Event Event::Home = Event::Special({27, 91, 72}); // NOLINT +const Event Event::End = Event::Special({27, 91, 70}); // NOLINT +const Event Event::PageUp = Event::Special({27, 91, 53, 126}); // NOLINT +const Event Event::PageDown = Event::Special({27, 91, 54, 126}); // NOLINT +const Event Event::Custom = Event::Special({0}); // NOLINT } // namespace ftxui diff --git a/src/ftxui/component/input.cpp b/src/ftxui/component/input.cpp index 1e3299389..a988cb149 100644 --- a/src/ftxui/component/input.cpp +++ b/src/ftxui/component/input.cpp @@ -1,5 +1,5 @@ -#include // for size_t #include // for max, min +#include // for size_t #include // for function #include // for shared_ptr, allocator #include // for string, wstring @@ -24,11 +24,12 @@ namespace ftxui { namespace { -std::string PasswordField(int size) { +std::string PasswordField(size_t size) { std::string out; out.reserve(2 * size); - while (size--) + while (size--) { out += "•"; + } return out; } @@ -38,21 +39,25 @@ class InputBase : public ComponentBase { InputBase(StringRef content, ConstStringRef placeholder, Ref option) - : content_(content), placeholder_(placeholder), option_(option) {} + : content_(std::move(content)), + placeholder_(std::move(placeholder)), + option_(std::move(option)) {} int cursor_position_internal_ = 0; int& cursor_position() { int& opt = option_->cursor_position(); - if (opt != -1) + if (opt != -1) { return opt; + } return cursor_position_internal_; } // Component implementation: Element Render() override { std::string password_content; - if (option_->password()) + if (option_->password()) { password_content = PasswordField(content_->size()); + } std::string& content = option_->password() ? password_content : *content_; int size = GlyphCount(content); @@ -65,19 +70,22 @@ class InputBase : public ComponentBase { if (size == 0) { bool hovered = hovered_; Decorator decorator = dim | main_decorator; - if (is_focused) + if (is_focused) { decorator = decorator | focus; - if (hovered || is_focused) + } + if (hovered || is_focused) { decorator = decorator | inverted; + } return text(*placeholder_) | decorator | reflect(box_); } // Not focused. if (!is_focused) { - if (hovered_) + if (hovered_) { return text(content) | main_decorator | inverted | reflect(box_); - else + } else { return text(content) | main_decorator | reflect(box_); + } } int index_before_cursor = GlyphPosition(content, cursor_position()); @@ -100,17 +108,19 @@ class InputBase : public ComponentBase { bool OnEvent(Event event) override { cursor_position() = - std::max(0, std::min(content_->size(), cursor_position())); + std::max(0, std::min((int)content_->size(), cursor_position())); - if (event.is_mouse()) + if (event.is_mouse()) { return OnMouseEvent(event); + } std::string c; // Backspace. if (event == Event::Backspace) { - if (cursor_position() == 0) + if (cursor_position() == 0) { return false; + } size_t start = GlyphPosition(*content_, cursor_position() - 1); size_t end = GlyphPosition(*content_, cursor_position()); content_->erase(start, end - start); @@ -121,8 +131,9 @@ class InputBase : public ComponentBase { // Delete if (event == Event::Delete) { - if (cursor_position() == int(content_->size())) + if (cursor_position() == int(content_->size())) { return false; + } size_t start = GlyphPosition(*content_, cursor_position()); size_t end = GlyphPosition(*content_, cursor_position() + 1); content_->erase(start, end - start); @@ -176,8 +187,9 @@ class InputBase : public ComponentBase { bool OnMouseEvent(Event event) { hovered_ = box_.Contain(event.mouse().x, event.mouse().y) && CaptureMouse(event); - if (!hovered_) + if (!hovered_) { return false; + } if (event.mouse().button != Mouse::Left || event.mouse().motion != Mouse::Pressed) { @@ -185,22 +197,24 @@ class InputBase : public ComponentBase { } TakeFocus(); - if (content_->size() == 0) + if (content_->empty()) { return true; + } auto mapping = CellToGlyphIndex(*content_); int original_glyph = cursor_position(); original_glyph = util::clamp(original_glyph, 0, int(mapping.size())); - int original_cell = 0; + size_t original_cell = 0; for (size_t i = 0; i < mapping.size(); i++) { if (mapping[i] == original_glyph) { - original_cell = i; + original_cell = (int)i; break; } } - if (mapping[original_cell] != original_glyph) + if (mapping[original_cell] != original_glyph) { original_cell = mapping.size(); - int target_cell = original_cell + event.mouse().x - cursor_box_.x_min; + } + int target_cell = int(original_cell) + event.mouse().x - cursor_box_.x_min; int target_glyph = target_cell < (int)mapping.size() ? mapping[target_cell] : (int)mapping.size(); target_glyph = util::clamp(target_glyph, 0, GlyphCount(*content_)); @@ -279,7 +293,8 @@ class WideInputBase : public InputBase { Component Input(StringRef content, ConstStringRef placeholder, Ref option) { - return Make(content, placeholder, std::move(option)); + return Make(std::move(content), std::move(placeholder), + std::move(option)); } /// @brief . An input box for editing text. @@ -307,7 +322,8 @@ Component Input(StringRef content, Component Input(WideStringRef content, ConstStringRef placeholder, Ref option) { - return Make(content, placeholder, std::move(option)); + return Make(std::move(content), std::move(placeholder), + std::move(option)); } } // namespace ftxui diff --git a/src/ftxui/component/maybe.cpp b/src/ftxui/component/maybe.cpp index 1644bfaae..f85c25def 100644 --- a/src/ftxui/component/maybe.cpp +++ b/src/ftxui/component/maybe.cpp @@ -13,7 +13,7 @@ namespace ftxui { Component Maybe(Component child, std::function show) { class Impl : public ComponentBase { public: - Impl(std::function show) : show_(std::move(show)) {} + explicit Impl(std::function show) : show_(std::move(show)) {} private: Element Render() override { @@ -48,7 +48,7 @@ Component Maybe(Component child, std::function show) { /// ``` ComponentDecorator Maybe(std::function show) { return [show = std::move(show)](Component child) mutable { - return Maybe(child, std::move(show)); + return Maybe(std::move(child), std::move(show)); }; } @@ -64,7 +64,7 @@ ComponentDecorator Maybe(std::function show) { /// auto maybe_component = Maybe(component, &show); /// ``` Component Maybe(Component child, const bool* show) { - return Maybe(child, [show] { return *show; }); + return Maybe(std::move(child), [show] { return *show; }); } /// @brief Decorate a component. It is shown only when |show| is true. @@ -78,7 +78,7 @@ Component Maybe(Component child, const bool* show) { /// auto maybe_component = component | Maybe(&show); /// ``` ComponentDecorator Maybe(const bool* show) { - return [show](Component child) { return Maybe(child, show); }; + return [show](Component child) { return Maybe(std::move(child), show); }; } } // namespace ftxui diff --git a/src/ftxui/component/menu.cpp b/src/ftxui/component/menu.cpp index d30191e73..0727c32e8 100644 --- a/src/ftxui/component/menu.cpp +++ b/src/ftxui/component/menu.cpp @@ -24,13 +24,15 @@ namespace ftxui { namespace { -Element DefaultOptionTransform(EntryState state) { - state.label = (state.active ? "> " : " ") + state.label; - Element e = text(state.label); - if (state.focused) +Element DefaultOptionTransform(const EntryState& state) { + std::string label = (state.active ? "> " : " ") + state.label; // NOLINT + Element e = text(label); + if (state.focused) { e = e | inverted; - if (state.active) + } + if (state.active) { e = e | bold; + } return e; } @@ -43,7 +45,7 @@ bool IsInverted(MenuOption::Direction direction) { case MenuOption::Direction::Right: return false; } - return false; // NOT_REACHED() + return false; // NOT_REACHED() } bool IsHorizontal(MenuOption::Direction direction) { @@ -55,7 +57,7 @@ bool IsHorizontal(MenuOption::Direction direction) { case MenuOption::Direction::Up: return false; } - return false; // NOT_REACHED() + return false; // NOT_REACHED() } } // namespace @@ -65,17 +67,19 @@ bool IsHorizontal(MenuOption::Direction direction) { class MenuBase : public ComponentBase { public: MenuBase(ConstStringListRef entries, int* selected, Ref option) - : entries_(entries), selected_(selected), option_(option) {} + : entries_(entries), selected_(selected), option_(std::move(option)) {} bool IsHorizontal() { return ftxui::IsHorizontal(option_->direction); } void OnChange() { - if (option_->on_change) + if (option_->on_change) { option_->on_change(); + } } void OnEnter() { - if (option_->on_enter) + if (option_->on_enter) { option_->on_enter(); + } } void Clamp() { @@ -87,10 +91,12 @@ class MenuBase : public ComponentBase { void OnAnimation(animation::Params& params) override { animator_first_.OnAnimation(params); animator_second_.OnAnimation(params); - for (auto& animator : animator_background_) + for (auto& animator : animator_background_) { animator.OnAnimation(params); - for (auto& animator : animator_foreground_) + } + for (auto& animator : animator_foreground_) { animator.OnAnimation(params); + } } Element Render() override { @@ -99,11 +105,13 @@ class MenuBase : public ComponentBase { Elements elements; bool is_menu_focused = Focused(); - if (option_->elements_prefix) + if (option_->elements_prefix) { elements.push_back(option_->elements_prefix()); + } for (int i = 0; i < size(); ++i) { - if (i != 0 && option_->elements_infix) + if (i != 0 && option_->elements_infix) { elements.push_back(option_->elements_infix()); + } bool is_focused = (focused_entry() == i) && is_menu_focused; bool is_selected = (*selected_ == i); @@ -120,21 +128,24 @@ class MenuBase : public ComponentBase { Element element = (option_->entries.transform ? option_->entries.transform : DefaultOptionTransform) // - (std::move(state)); + (state); elements.push_back(element | AnimatedColorStyle(i) | reflect(boxes_[i]) | focus_management); } - if (option_->elements_postfix) + if (option_->elements_postfix) { elements.push_back(option_->elements_postfix()); + } - if (IsInverted(option_->direction)) + if (IsInverted(option_->direction)) { std::reverse(elements.begin(), elements.end()); + } Element bar = IsHorizontal() ? hbox(std::move(elements)) : vbox(std::move(elements)); - if (!option_->underline.enabled) + if (!option_->underline.enabled) { return bar | reflect(box_); + } if (IsHorizontal()) { return vbox({ @@ -211,36 +222,49 @@ class MenuBase : public ComponentBase { } } + // NOLINTNEXTLINE(readability-function-cognitive-complexity) bool OnEvent(Event event) override { Clamp(); - if (!CaptureMouse(event)) + if (!CaptureMouse(event)) { return false; + } - if (event.is_mouse()) + if (event.is_mouse()) { return OnMouseEvent(event); + } if (Focused()) { int old_selected = *selected_; - if (event == Event::ArrowUp || event == Event::Character('k')) + if (event == Event::ArrowUp || event == Event::Character('k')) { OnUp(); - if (event == Event::ArrowDown || event == Event::Character('j')) + } + if (event == Event::ArrowDown || event == Event::Character('j')) { OnDown(); - if (event == Event::ArrowLeft || event == Event::Character('h')) + } + if (event == Event::ArrowLeft || event == Event::Character('h')) { OnLeft(); - if (event == Event::ArrowRight || event == Event::Character('l')) + } + if (event == Event::ArrowRight || event == Event::Character('l')) { OnRight(); - if (event == Event::PageUp) + } + if (event == Event::PageUp) { (*selected_) -= box_.y_max - box_.y_min; - if (event == Event::PageDown) + } + if (event == Event::PageDown) { (*selected_) += box_.y_max - box_.y_min; - if (event == Event::Home) + } + if (event == Event::Home) { (*selected_) = 0; - if (event == Event::End) + } + if (event == Event::End) { (*selected_) = size() - 1; - if (event == Event::Tab && size()) + } + if (event == Event::Tab && size()) { *selected_ = (*selected_ + 1) % size(); - if (event == Event::TabReverse && size()) + } + if (event == Event::TabReverse && size()) { *selected_ = (*selected_ + size() - 1) % size(); + } *selected_ = util::clamp(*selected_, 0, size() - 1); @@ -269,11 +293,13 @@ class MenuBase : public ComponentBase { event.mouse().button != Mouse::Left) { return false; } - if (!CaptureMouse(event)) + if (!CaptureMouse(event)) { return false; + } for (int i = 0; i < size(); ++i) { - if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) + if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) { continue; + } TakeFocus(); focused_entry() = i; @@ -290,19 +316,23 @@ class MenuBase : public ComponentBase { } bool OnMouseWheel(Event event) { - if (!box_.Contain(event.mouse().x, event.mouse().y)) + if (!box_.Contain(event.mouse().x, event.mouse().y)) { return false; + } int old_selected = *selected_; - if (event.mouse().button == Mouse::WheelUp) + if (event.mouse().button == Mouse::WheelUp) { (*selected_)--; - if (event.mouse().button == Mouse::WheelDown) + } + if (event.mouse().button == Mouse::WheelDown) { (*selected_)++; + } *selected_ = util::clamp(*selected_, 0, size() - 1); - if (*selected_ != old_selected) + if (*selected_ != old_selected) { OnChange(); + } return true; } @@ -319,12 +349,12 @@ class MenuBase : public ComponentBase { animator_foreground_.clear(); for (int i = 0; i < size(); ++i) { - animation_background_[i] = 0.f; - animation_foreground_[i] = 0.f; - animator_background_.emplace_back(&animation_background_[i], 0.f, + animation_background_[i] = 0.F; + animation_foreground_[i] = 0.F; + animator_background_.emplace_back(&animation_background_[i], 0.F, std::chrono::milliseconds(0), animation::easing::Linear); - animator_foreground_.emplace_back(&animation_foreground_[i], 0.f, + animator_foreground_.emplace_back(&animation_foreground_[i], 0.F, std::chrono::milliseconds(0), animation::easing::Linear); } @@ -334,7 +364,7 @@ class MenuBase : public ComponentBase { for (int i = 0; i < size(); ++i) { bool is_focused = (focused_entry() == i) && is_menu_focused; bool is_selected = (*selected_ == i); - float target = is_selected ? 1.f : is_focused ? 0.5f : 0.f; + float target = is_selected ? 1.F : is_focused ? 0.5F : 0.F; // NOLINT if (animator_background_[i].to() != target) { animator_background_[i] = animation::Animator( &animation_background_[i], target, @@ -367,8 +397,9 @@ class MenuBase : public ComponentBase { } void UpdateUnderlineTarget() { - if (!option_->underline.enabled) + if (!option_->underline.enabled) { return; + } if (FirstTarget() == animator_first_.to() && SecondTarget() == animator_second_.to()) { @@ -398,32 +429,36 @@ class MenuBase : public ComponentBase { bool Focusable() const final { return entries_.size(); } int& focused_entry() { return option_->focused_entry(); } - int size() const { return entries_.size(); } - int FirstTarget() { - if (boxes_.size() == 0) - return 0; - return IsHorizontal() ? boxes_[*selected_].x_min - box_.x_min - : boxes_[*selected_].y_min - box_.y_min; + int size() const { return int(entries_.size()); } + float FirstTarget() { + if (boxes_.empty()) { + return 0.F; + } + int value = IsHorizontal() ? boxes_[*selected_].x_min - box_.x_min + : boxes_[*selected_].y_min - box_.y_min; + return float(value); } - int SecondTarget() { - if (boxes_.size() == 0) - return 0; - return IsHorizontal() ? boxes_[*selected_].x_max - box_.x_min - : boxes_[*selected_].y_max - box_.y_min; + float SecondTarget() { + if (boxes_.empty()) { + return 0.F; + } + int value = IsHorizontal() ? boxes_[*selected_].x_max - box_.x_min + : boxes_[*selected_].y_max - box_.y_min; + return float(value); } protected: ConstStringListRef entries_; - int* selected_ = 0; + int* selected_ = nullptr; Ref option_; std::vector boxes_; Box box_; - float first_ = 0.f; - float second_ = 0.f; - animation::Animator animator_first_ = animation::Animator(&first_, 0.f); - animation::Animator animator_second_ = animation::Animator(&second_, 0.f); + float first_ = 0.F; + float second_ = 0.F; + animation::Animator animator_first_ = animation::Animator(&first_, 0.F); + animation::Animator animator_second_ = animation::Animator(&second_, 0.F); std::vector animator_background_; std::vector animator_foreground_; @@ -519,7 +554,7 @@ Component MenuEntry(ConstStringRef label, Ref option) { Element element = (option_->transform ? option_->transform : DefaultOptionTransform) // - (std::move(state)); + (state); auto focus_management = focused ? select : nothing; return element | AnimatedColorStyle() | focus_management | reflect(box_); @@ -527,9 +562,10 @@ Component MenuEntry(ConstStringRef label, Ref option) { void UpdateAnimationTarget() { bool focused = Focused(); - float target = focused ? 1.0f : hovered_ ? 0.5f : 0.0f; - if (target == animator_background_.to()) + float target = focused ? 1.F : hovered_ ? 0.5F : 0.F; // NOLINT + if (target == animator_background_.to()) { return; + } animator_background_ = animation::Animator(&animation_background_, target, option_->animated_colors.background.duration, @@ -560,13 +596,15 @@ Component MenuEntry(ConstStringRef label, Ref option) { bool Focusable() const override { return true; } bool OnEvent(Event event) override { - if (!event.is_mouse()) + if (!event.is_mouse()) { return false; + } hovered_ = box_.Contain(event.mouse().x, event.mouse().y); - if (!hovered_) + if (!hovered_) { return false; + } if (event.mouse().button == Mouse::Left && event.mouse().motion == Mouse::Released) { @@ -587,12 +625,12 @@ Component MenuEntry(ConstStringRef label, Ref option) { Box box_; bool hovered_ = false; - float animation_background_ = 0.f; - float animation_foreground_ = 0.f; + float animation_background_ = 0.F; + float animation_foreground_ = 0.F; animation::Animator animator_background_ = - animation::Animator(&animation_background_, 0.f); + animation::Animator(&animation_background_, 0.F); animation::Animator animator_foreground_ = - animation::Animator(&animation_foreground_, 0.f); + animation::Animator(&animation_foreground_, 0.F); }; return Make(std::move(label), std::move(option)); diff --git a/src/ftxui/component/radiobox.cpp b/src/ftxui/component/radiobox.cpp index 157c7fe9a..298518d3b 100644 --- a/src/ftxui/component/radiobox.cpp +++ b/src/ftxui/component/radiobox.cpp @@ -1,21 +1,20 @@ #include // for max #include // for function #include // for shared_ptr, allocator_traits<>::value_type -#include // for string #include // for move #include // for vector #include "ftxui/component/captured_mouse.hpp" // for CapturedMouse #include "ftxui/component/component.hpp" // for Make, Radiobox #include "ftxui/component/component_base.hpp" // for ComponentBase -#include "ftxui/component/component_options.hpp" // for RadioboxOption +#include "ftxui/component/component_options.hpp" // for RadioboxOption, EntryState #include "ftxui/component/event.hpp" // for Event, Event::ArrowDown, Event::ArrowUp, Event::End, Event::Home, Event::PageDown, Event::PageUp, Event::Return, Event::Tab, Event::TabReverse #include "ftxui/component/mouse.hpp" // for Mouse, Mouse::WheelDown, Mouse::WheelUp, Mouse::Left, Mouse::Released #include "ftxui/component/screen_interactive.hpp" // for Component -#include "ftxui/dom/elements.hpp" // for operator|, reflect, text, Element, hbox, vbox, Elements, focus, nothing, select -#include "ftxui/screen/box.hpp" // for Box -#include "ftxui/screen/util.hpp" // for clamp -#include "ftxui/util/ref.hpp" // for Ref, ConstStringListRef +#include "ftxui/dom/elements.hpp" // for operator|, reflect, Element, vbox, Elements, focus, nothing, select +#include "ftxui/screen/box.hpp" // for Box +#include "ftxui/screen/util.hpp" // for clamp +#include "ftxui/util/ref.hpp" // for Ref, ConstStringListRef namespace ftxui { @@ -50,41 +49,51 @@ class RadioboxBase : public ComponentBase { is_focused, }; auto element = - (option_->transform - ? option_->transform - : RadioboxOption::Simple().transform)(std::move(state)); + (option_->transform ? option_->transform + : RadioboxOption::Simple().transform)(state); elements.push_back(element | focus_management | reflect(boxes_[i])); } return vbox(std::move(elements)) | reflect(box_); } + // NOLINTNEXTLINE(readability-function-cognitive-complexity) bool OnEvent(Event event) override { Clamp(); - if (!CaptureMouse(event)) + if (!CaptureMouse(event)) { return false; + } - if (event.is_mouse()) + if (event.is_mouse()) { return OnMouseEvent(event); + } if (Focused()) { int old_hovered = hovered_; - if (event == Event::ArrowUp || event == Event::Character('k')) + if (event == Event::ArrowUp || event == Event::Character('k')) { (hovered_)--; - if (event == Event::ArrowDown || event == Event::Character('j')) + } + if (event == Event::ArrowDown || event == Event::Character('j')) { (hovered_)++; - if (event == Event::PageUp) + } + if (event == Event::PageUp) { (hovered_) -= box_.y_max - box_.y_min; - if (event == Event::PageDown) + } + if (event == Event::PageDown) { (hovered_) += box_.y_max - box_.y_min; - if (event == Event::Home) + } + if (event == Event::Home) { (hovered_) = 0; - if (event == Event::End) + } + if (event == Event::End) { (hovered_) = size() - 1; - if (event == Event::Tab && size()) + } + if (event == Event::Tab && size()) { hovered_ = (hovered_ + 1) % size(); - if (event == Event::TabReverse && size()) + } + if (event == Event::TabReverse && size()) { hovered_ = (hovered_ + size() - 1) % size(); + } hovered_ = util::clamp(hovered_, 0, size() - 1); @@ -111,8 +120,9 @@ class RadioboxBase : public ComponentBase { } for (int i = 0; i < size(); ++i) { - if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) + if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) { continue; + } TakeFocus(); focused_entry() = i; @@ -130,20 +140,24 @@ class RadioboxBase : public ComponentBase { } bool OnMouseWheel(Event event) { - if (!box_.Contain(event.mouse().x, event.mouse().y)) + if (!box_.Contain(event.mouse().x, event.mouse().y)) { return false; + } int old_hovered = hovered_; - if (event.mouse().button == Mouse::WheelUp) + if (event.mouse().button == Mouse::WheelUp) { (hovered_)--; - if (event.mouse().button == Mouse::WheelDown) + } + if (event.mouse().button == Mouse::WheelDown) { (hovered_)++; + } hovered_ = util::clamp(hovered_, 0, size() - 1); - if (hovered_ != old_hovered) + if (hovered_ != old_hovered) { option_->on_change(); + } return true; } @@ -157,7 +171,7 @@ class RadioboxBase : public ComponentBase { bool Focusable() const final { return entries_.size(); } int& focused_entry() { return option_->focused_entry(); } - int size() const { return entries_.size(); } + int size() const { return int(entries_.size()); } ConstStringListRef entries_; int* selected_; diff --git a/src/ftxui/component/renderer.cpp b/src/ftxui/component/renderer.cpp index d7c0c1c60..82300fe7f 100644 --- a/src/ftxui/component/renderer.cpp +++ b/src/ftxui/component/renderer.cpp @@ -28,7 +28,8 @@ namespace ftxui { Component Renderer(std::function render) { class Impl : public ComponentBase { public: - Impl(std::function render) : render_(std::move(render)) {} + explicit Impl(std::function render) + : render_(std::move(render)) {} Element Render() override { return render_(); } std::function render_; }; @@ -82,15 +83,17 @@ Component Renderer(Component child, std::function render) { Component Renderer(std::function render) { class Impl : public ComponentBase { public: - Impl(std::function render) : render_(std::move(render)) {} + explicit 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)) + if (!CaptureMouse(event)) { return false; + } TakeFocus(); } @@ -118,8 +121,8 @@ Component Renderer(std::function render) { /// | Renderer(inverted); /// screen.Loop(renderer); /// ``` -ComponentDecorator Renderer(ElementDecorator decorator) { - return [decorator](Component component) { +ComponentDecorator Renderer(ElementDecorator decorator) { // NOLINT + return [decorator](Component component) { // NOLINT return Renderer(component, [component, decorator] { return component->Render() | decorator; }); diff --git a/src/ftxui/component/resizable_split.cpp b/src/ftxui/component/resizable_split.cpp index d6efd1e7b..85be4bd9c 100644 --- a/src/ftxui/component/resizable_split.cpp +++ b/src/ftxui/component/resizable_split.cpp @@ -15,16 +15,19 @@ namespace { class ResizableSplitLeftBase : public ComponentBase { public: ResizableSplitLeftBase(Component main, Component child, int* main_size) - : main_(main), child_(child), main_size_(main_size) { + : main_(std::move(main)), + child_(std::move(child)), + main_size_(main_size) { Add(Container::Horizontal({ - main, - child, + main_, + child_, })); } bool OnEvent(Event event) final { - if (event.is_mouse()) + if (event.is_mouse()) { return OnMouseEvent(std::move(event)); + } return ComponentBase::OnEvent(std::move(event)); } @@ -71,16 +74,19 @@ class ResizableSplitLeftBase : public ComponentBase { class ResizableSplitRightBase : public ComponentBase { public: ResizableSplitRightBase(Component main, Component child, int* main_size) - : main_(main), child_(child), main_size_(main_size) { + : main_(std::move(main)), + child_(std::move(child)), + main_size_(main_size) { Add(Container::Horizontal({ - child, - main, + child_, + main_, })); } bool OnEvent(Event event) final { - if (event.is_mouse()) + if (event.is_mouse()) { return OnMouseEvent(std::move(event)); + } return ComponentBase::OnEvent(std::move(event)); } @@ -127,16 +133,19 @@ class ResizableSplitRightBase : public ComponentBase { class ResizableSplitTopBase : public ComponentBase { public: ResizableSplitTopBase(Component main, Component child, int* main_size) - : main_(main), child_(child), main_size_(main_size) { + : main_(std::move(main)), + child_(std::move(child)), + main_size_(main_size) { Add(Container::Vertical({ - main, - child, + main_, + child_, })); } bool OnEvent(Event event) final { - if (event.is_mouse()) + if (event.is_mouse()) { return OnMouseEvent(std::move(event)); + } return ComponentBase::OnEvent(std::move(event)); } @@ -183,16 +192,19 @@ class ResizableSplitTopBase : public ComponentBase { class ResizableSplitBottomBase : public ComponentBase { public: ResizableSplitBottomBase(Component main, Component child, int* main_size) - : main_(main), child_(child), main_size_(main_size) { + : main_(std::move(main)), + child_(std::move(child)), + main_size_(main_size) { Add(Container::Vertical({ - child, - main, + child_, + main_, })); } bool OnEvent(Event event) final { - if (event.is_mouse()) + if (event.is_mouse()) { return OnMouseEvent(std::move(event)); + } return ComponentBase::OnEvent(std::move(event)); } diff --git a/src/ftxui/component/screen_interactive.cpp b/src/ftxui/component/screen_interactive.cpp index db9680cef..8a7b4e089 100644 --- a/src/ftxui/component/screen_interactive.cpp +++ b/src/ftxui/component/screen_interactive.cpp @@ -1,15 +1,15 @@ -#include // for fileno, stdin #include // for copy, max, min -#include // for operator-, duration, operator>=, milliseconds, time_point, common_type<>::type +#include // for array +#include // for operator-, milliseconds, duration, operator>=, time_point, common_type<>::type #include // for signal, raise, SIGTSTP, SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM, SIGWINCH -#include // for NULL +#include // for fileno, size_t, stdin #include // for function #include // for initializer_list #include // for cout, ostream, basic_ostream, operator<<, endl, flush #include // for stack #include // for thread, sleep_for #include // for decay_t -#include // for swap, move +#include // for move, swap #include // for visit #include // for vector @@ -50,14 +50,15 @@ namespace ftxui { namespace animation { void RequestAnimationFrame() { auto* screen = ScreenInteractive::Active(); - if (screen) + if (screen) { screen->RequestAnimationFrame(); + } } } // namespace animation namespace { -ScreenInteractive* g_active_screen = nullptr; +ScreenInteractive* g_active_screen = nullptr; // NOLINT void Flush() { // Emscripten doesn't implement flush. We interpret zero as flush. @@ -138,16 +139,14 @@ void EventListener(std::atomic* quit, Sender out) { int CheckStdinReady(int usec_timeout) { timeval tv = {0, usec_timeout}; fd_set fds; - FD_ZERO(&fds); - FD_SET(STDIN_FILENO, &fds); - select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv); - return FD_ISSET(STDIN_FILENO, &fds); + FD_ZERO(&fds); // NOLINT + FD_SET(STDIN_FILENO, &fds); // NOLINT + select(STDIN_FILENO + 1, &fds, nullptr, nullptr, &tv); // NOLINT + return FD_ISSET(STDIN_FILENO, &fds); // NOLINT } // Read char from the terminal. void EventListener(std::atomic* quit, Sender out) { - const int buffer_size = 100; - auto parser = TerminalInputParser(std::move(out)); while (!*quit) { @@ -156,16 +155,18 @@ void EventListener(std::atomic* quit, Sender out) { continue; } - char buff[buffer_size]; - int l = read(fileno(stdin), buff, buffer_size); - for (int i = 0; i < l; ++i) - parser.Add(buff[i]); + const size_t buffer_size = 100; + std::array buffer; // NOLINT; + int l = read(fileno(stdin), buffer.data(), buffer_size); // NOLINT + for (int i = 0; i < l; ++i) { + parser.Add(buffer[i]); // NOLINT + } } } #endif -const std::string CSI = "\x1b["; +const std::string CSI = "\x1b["; // NOLINT // DEC: Digital Equipment Corporation enum class DECMode { @@ -186,12 +187,13 @@ enum class DSRMode { kCursor = 6, }; -const std::string Serialize(std::vector parameters) { +std::string Serialize(const std::vector& parameters) { bool first = true; std::string out; for (DECMode parameter : parameters) { - if (!first) + if (!first) { out += ";"; + } out += std::to_string(int(parameter)); first = false; } @@ -199,22 +201,22 @@ const std::string Serialize(std::vector parameters) { } // DEC Private Mode Set (DECSET) -const std::string Set(std::vector parameters) { +std::string Set(const std::vector& parameters) { return CSI + "?" + Serialize(parameters) + "h"; } // DEC Private Mode Reset (DECRST) -const std::string Reset(std::vector parameters) { +std::string Reset(const std::vector& parameters) { return CSI + "?" + Serialize(parameters) + "l"; } // Device Status Report (DSR) -const std::string DeviceStatusReport(DSRMode ps) { +std::string DeviceStatusReport(DSRMode ps) { return CSI + std::to_string(int(ps)) + "n"; } using SignalHandler = void(int); -std::stack on_exit_functions; +std::stack on_exit_functions; // NOLINT void OnExit(int signal) { (void)signal; while (!on_exit_functions.empty()) { @@ -223,14 +225,14 @@ void OnExit(int signal) { } } -auto install_signal_handler = [](int sig, SignalHandler handler) { +const auto install_signal_handler = [](int sig, SignalHandler handler) { auto old_signal_handler = std::signal(sig, handler); on_exit_functions.push([=] { std::signal(sig, old_signal_handler); }); }; -Closure on_resize = [] {}; +Closure g_on_resize = [] {}; // NOLINT void OnResize(int /* signal */) { - on_resize(); + g_on_resize(); } void OnSigStop(int /*signal*/) { @@ -239,17 +241,24 @@ void OnSigStop(int /*signal*/) { class CapturedMouseImpl : public CapturedMouseInterface { public: - CapturedMouseImpl(std::function callback) : callback_(callback) {} + explicit CapturedMouseImpl(std::function callback) + : callback_(std::move(callback)) {} ~CapturedMouseImpl() override { callback_(); } + CapturedMouseImpl(const CapturedMouseImpl&) = delete; + CapturedMouseImpl(CapturedMouseImpl&&) = delete; + CapturedMouseImpl& operator=(const CapturedMouseImpl&) = delete; + CapturedMouseImpl& operator=(CapturedMouseImpl&&) = delete; private: std::function callback_; }; void AnimationListener(std::atomic* quit, Sender out) { + // Animation at around 60fps. + const auto time_delta = std::chrono::milliseconds(15); while (!*quit) { out->Send(AnimationTask()); - std::this_thread::sleep_for(std::chrono::milliseconds(15)); + std::this_thread::sleep_for(time_delta); } } @@ -286,31 +295,36 @@ ScreenInteractive ScreenInteractive::FitComponent() { } void ScreenInteractive::Post(Task task) { - if (!quit_) - task_sender_->Send(task); + if (!quit_) { + task_sender_->Send(std::move(task)); + } } void ScreenInteractive::PostEvent(Event event) { Post(event); } void ScreenInteractive::RequestAnimationFrame() { - if (animation_requested_) + if (animation_requested_) { return; + } animation_requested_ = true; auto now = animation::Clock::now(); - if (now - previous_animation_time >= std::chrono::milliseconds(33)) + const auto time_histeresis = std::chrono::milliseconds(33); + if (now - previous_animation_time >= time_histeresis) { previous_animation_time = now; + } } CapturedMouse ScreenInteractive::CaptureMouse() { - if (mouse_captured) + if (mouse_captured) { return nullptr; + } mouse_captured = true; return std::make_unique( [this] { mouse_captured = false; }); } -void ScreenInteractive::Loop(Component component) { +void ScreenInteractive::Loop(Component component) { // NOLINT // Suspend previously active screen: if (g_active_screen) { std::swap(suspended_screen_, g_active_screen); @@ -324,7 +338,7 @@ void ScreenInteractive::Loop(Component component) { // This screen is now active: g_active_screen = this; g_active_screen->Install(); - g_active_screen->Main(component); + g_active_screen->Main(std::move(component)); g_active_screen->Uninstall(); g_active_screen = nullptr; @@ -348,7 +362,7 @@ void ScreenInteractive::Loop(Component component) { /// @brief Decorate a function. It executes the same way, but with the currently /// active screen terminal hooks temporarilly uninstalled during its execution. /// @param fn The function to decorate. -Closure ScreenInteractive::WithRestoredIO(Closure fn) { +Closure ScreenInteractive::WithRestoredIO(Closure fn) { // NOLINT return [this, fn] { Uninstall(); fn(); @@ -370,10 +384,11 @@ void ScreenInteractive::Install() { // Install signal handlers to restore the terminal state on exit. The default // signal handlers are restored on exit. - for (int signal : {SIGTERM, SIGSEGV, SIGINT, SIGILL, SIGABRT, SIGFPE}) + for (int signal : {SIGTERM, SIGSEGV, SIGINT, SIGILL, SIGABRT, SIGFPE}) { install_signal_handler(signal, OnExit); + } - // Save the old terminal configuration and restore it on exit. + // Save the old terminal configuration and restore it on exit. #if defined(_WIN32) // Enable VT processing on stdout and stdin auto stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); @@ -405,12 +420,12 @@ void ScreenInteractive::Install() { SetConsoleMode(stdin_handle, in_mode); SetConsoleMode(stdout_handle, out_mode); #else - struct termios terminal; + struct termios terminal; // NOLINT tcgetattr(STDIN_FILENO, &terminal); on_exit_functions.push([=] { tcsetattr(STDIN_FILENO, TCSANOW, &terminal); }); - terminal.c_lflag &= ~ICANON; // Non canonique terminal. - terminal.c_lflag &= ~ECHO; // Do not print after a key press. + terminal.c_lflag &= ~ICANON; // NOLINT Non canonique terminal. + terminal.c_lflag &= ~ECHO; // NOLINT Do not print after a key press. terminal.c_cc[VMIN] = 0; terminal.c_cc[VTIME] = 0; // auto oldf = fcntl(STDIN_FILENO, F_GETFL, 0); @@ -420,19 +435,19 @@ void ScreenInteractive::Install() { tcsetattr(STDIN_FILENO, TCSANOW, &terminal); // Handle resize. - on_resize = [&] { task_sender_->Send(Event::Special({0})); }; + g_on_resize = [&] { task_sender_->Send(Event::Special({0})); }; install_signal_handler(SIGWINCH, OnResize); // Handle SIGTSTP/SIGCONT. install_signal_handler(SIGTSTP, OnSigStop); #endif - auto enable = [&](std::vector parameters) { + auto enable = [&](const std::vector& parameters) { std::cout << Set(parameters); on_exit_functions.push([=] { std::cout << Reset(parameters); }); }; - auto disable = [&](std::vector parameters) { + auto disable = [&](const std::vector& parameters) { std::cout << Reset(parameters); on_exit_functions.push([=] { std::cout << Set(parameters); }); }; @@ -475,6 +490,7 @@ void ScreenInteractive::Uninstall() { OnExit(0); } +// NOLINTNEXTLINE void ScreenInteractive::Main(Component component) { previous_animation_time = animation::Clock::now(); @@ -493,8 +509,9 @@ void ScreenInteractive::Main(Component component) { } Task task; - if (!task_receiver_->Receive(&task)) + if (!task_receiver_->Receive(&task)) { break; + } // clang-format off std::visit([&](auto&& arg) { @@ -527,8 +544,9 @@ void ScreenInteractive::Main(Component component) { // Handle Animation if constexpr (std::is_same_v) { - if (!animation_requested_) + if (!animation_requested_) { return; + } animation_requested_ = false; animation::TimePoint now = animation::Clock::now(); @@ -546,6 +564,7 @@ void ScreenInteractive::Main(Component component) { } } +// NOLINTNEXTLINE void ScreenInteractive::Draw(Component component) { auto document = component->Render(); int dimx = 0; @@ -596,13 +615,16 @@ void ScreenInteractive::Draw(Component component) { // https://github.com/ArthurSonzogni/FTXUI/issues/136 static int i = -3; ++i; - if (!use_alternative_screen_ && (i % 150 == 0)) + if (!use_alternative_screen_ && (i % 150 == 0)) { // NOLINT std::cout << DeviceStatusReport(DSRMode::kCursor); + } #else static int i = -3; ++i; - if (!use_alternative_screen_ && (previous_frame_resized_ || i % 40 == 0)) + if (!use_alternative_screen_ && + (previous_frame_resized_ || i % 40 == 0)) { // NOLINT std::cout << DeviceStatusReport(DSRMode::kCursor); + } #endif previous_frame_resized_ = resized; diff --git a/src/ftxui/component/slider.cpp b/src/ftxui/component/slider.cpp index 5b59bf867..1194c6396 100644 --- a/src/ftxui/component/slider.cpp +++ b/src/ftxui/component/slider.cpp @@ -18,13 +18,13 @@ template class SliderBase : public ComponentBase { public: SliderBase(ConstStringRef label, T* value, T min, T max, T increment) - : label_(label), + : label_(std::move(label)), value_(value), min_(min), max_(max), increment_(increment) {} - Element Render() { + Element Render() override { auto gauge_color = Focused() ? color(Color::GrayLight) : color(Color::GrayDark); float percent = float(*value_ - min_) / float(max_ - min_); @@ -40,8 +40,9 @@ class SliderBase : public ComponentBase { } bool OnEvent(Event event) final { - if (event.is_mouse()) + if (event.is_mouse()) { return OnMouseEvent(event); + } if (event == Event::ArrowLeft || event == Event::Character('h')) { *value_ -= increment_; diff --git a/src/ftxui/component/terminal_input_parser.cpp b/src/ftxui/component/terminal_input_parser.cpp index ae9f45aa6..38860ad40 100644 --- a/src/ftxui/component/terminal_input_parser.cpp +++ b/src/ftxui/component/terminal_input_parser.cpp @@ -14,11 +14,14 @@ TerminalInputParser::TerminalInputParser(Sender out) void TerminalInputParser::Timeout(int time) { timeout_ += time; - if (timeout_ < 50) + const int timeout_threshold = 50; + if (timeout_ < timeout_threshold) { return; + } timeout_ = 0; - if (pending_.size()) + if (!pending_.empty()) { Send(SPECIAL); + } } void TerminalInputParser::Add(char c) { @@ -56,21 +59,23 @@ void TerminalInputParser::Send(TerminalInputParser::Output output) { // key. This also happens with linux with the `bind` command: // See https://github.com/ArthurSonzogni/FTXUI/issues/337 // Here, we uniformize the new line character to `\n`. - if (pending_ == "\r") + if (pending_ == "\r") { out_->Send(Event::Special("\n")); - else + } else { out_->Send(Event::Special(std::move(pending_))); + } pending_.clear(); return; case MOUSE: - out_->Send(Event::Mouse(std::move(pending_), output.mouse)); + out_->Send(Event::Mouse(std::move(pending_), output.mouse)); // NOLINT pending_.clear(); return; case CURSOR_REPORTING: - out_->Send(Event::CursorReporting(std::move(pending_), output.cursor.x, - output.cursor.y)); + out_->Send(Event::CursorReporting(std::move(pending_), // NOLINT + output.cursor.x, // NOLINT + output.cursor.y)); // NOLINT pending_.clear(); return; } @@ -78,12 +83,13 @@ void TerminalInputParser::Send(TerminalInputParser::Output output) { } TerminalInputParser::Output TerminalInputParser::Parse() { - if (!Eat()) + if (!Eat()) { return UNCOMPLETED; + } switch (Current()) { - case 24: // CAN - case 26: // SUB + case 24: // CAN NOLINT + case 26: // SUB NOLINT return DROP; case '\x1B': @@ -92,11 +98,13 @@ TerminalInputParser::Output TerminalInputParser::Parse() { break; } - if (Current() < 32) // C0 + if (Current() < 32) { // C0 NOLINT return SPECIAL; + } - if (Current() == 127) // Delete + if (Current() == 127) { // Delete // NOLINT return SPECIAL; + } return ParseUTF8(); } @@ -118,18 +126,18 @@ TerminalInputParser::Output TerminalInputParser::Parse() { // Then some sequences are illegal if it exist a shorter representation of the // same codepoint. TerminalInputParser::Output TerminalInputParser::ParseUTF8() { - unsigned char head = static_cast(Current()); - unsigned char selector = 0b1000'0000; + auto head = static_cast(Current()); + unsigned char selector = 0b1000'0000; // NOLINT // The non code-point part of the first byte. unsigned char mask = selector; // Find the first zero in the first byte. - int first_zero = 8; - for (int i = 0; i < 8; ++i) { + unsigned int first_zero = 8; // NOLINT + for (unsigned int i = 0; i < 8; ++i) { // NOLINT mask |= selector; if (head & selector) { - selector >>= 1; + selector >>= 1U; continue; } first_zero = i; @@ -137,48 +145,54 @@ TerminalInputParser::Output TerminalInputParser::ParseUTF8() { } // Accumulate the value of the first byte. - uint32_t value = head & ~mask; + auto value = uint32_t(head & ~mask); // NOLINT // Invalid UTF8, with more than 5 bytes. - if (first_zero == 1 || first_zero >= 5) + const unsigned int max_utf8_bytes = 5; + if (first_zero == 1 || first_zero >= max_utf8_bytes) { return DROP; + } // Multi byte UTF-8. - for (int i = 2; i <= first_zero; ++i) { - if (!Eat()) + for (unsigned int i = 2; i <= first_zero; ++i) { + if (!Eat()) { return UNCOMPLETED; + } // Invalid continuation byte. head = static_cast(Current()); - if ((head & 0b1100'0000) != 0b1000'0000) + if ((head & 0b1100'0000) != 0b1000'0000) { // NOLINT return DROP; - value <<= 6; - value += head & 0b0011'1111; + } + value <<= 6; // NOLINT + value += head & 0b0011'1111; // NOLINT } // Check for overlong UTF8 encoding. - int extra_byte; - if (value <= 0b000'0000'0111'1111) { - extra_byte = 0; - } else if (value <= 0b000'0111'1111'1111) { - extra_byte = 1; - } else if (value <= 0b1111'1111'1111'1111) { - extra_byte = 2; - } else if (value <= 0b1'0000'1111'1111'1111'1111) { - extra_byte = 3; - } else { + int extra_byte = 0; + if (value <= 0b000'0000'0111'1111) { // NOLINT + extra_byte = 0; // NOLINT + } else if (value <= 0b000'0111'1111'1111) { // NOLINT + extra_byte = 1; // NOLINT + } else if (value <= 0b1111'1111'1111'1111) { // NOLINT + extra_byte = 2; // NOLINT + } else if (value <= 0b1'0000'1111'1111'1111'1111) { // NOLINT + extra_byte = 3; // NOLINT + } else { // NOLINT return DROP; } - if (extra_byte != position_) + if (extra_byte != position_) { return DROP; + } return CHARACTER; } TerminalInputParser::Output TerminalInputParser::ParseESC() { - if (!Eat()) + if (!Eat()) { return UNCOMPLETED; + } switch (Current()) { case 'P': return ParseDCS(); @@ -187,26 +201,32 @@ TerminalInputParser::Output TerminalInputParser::ParseESC() { case ']': return ParseOSC(); default: - if (!Eat()) + if (!Eat()) { return UNCOMPLETED; - return SPECIAL; + } else { + return SPECIAL; + } } } TerminalInputParser::Output TerminalInputParser::ParseDCS() { // Parse until the string terminator ST. - while (1) { - if (!Eat()) + while (true) { + if (!Eat()) { return UNCOMPLETED; + } - if (Current() != '\x1B') + if (Current() != '\x1B') { continue; + } - if (!Eat()) + if (!Eat()) { return UNCOMPLETED; + } - if (Current() != '\\') + if (Current() != '\\') { continue; + } return SPECIAL; } @@ -217,8 +237,9 @@ TerminalInputParser::Output TerminalInputParser::ParseCSI() { int argument = 0; std::vector arguments; while (true) { - if (!Eat()) + if (!Eat()) { return UNCOMPLETED; + } if (Current() == '<') { altered = true; @@ -226,7 +247,7 @@ TerminalInputParser::Output TerminalInputParser::ParseCSI() { } if (Current() >= '0' && Current() <= '9') { - argument *= 10; + argument *= 10; // NOLINT argument += int(Current() - '0'); continue; } @@ -239,7 +260,7 @@ TerminalInputParser::Output TerminalInputParser::ParseCSI() { if (Current() >= ' ' && Current() <= '~' && Current() != '<') { arguments.push_back(argument); - argument = 0; + argument = 0; // NOLINT switch (Current()) { case 'M': return ParseMouse(altered, true, std::move(arguments)); @@ -253,53 +274,61 @@ TerminalInputParser::Output TerminalInputParser::ParseCSI() { } // Invalid ESC in CSI. - if (Current() == '\x1B') + if (Current() == '\x1B') { return SPECIAL; + } } } TerminalInputParser::Output TerminalInputParser::ParseOSC() { // Parse until the string terminator ST. while (true) { - if (!Eat()) + if (!Eat()) { return UNCOMPLETED; - if (Current() != '\x1B') + } + if (Current() != '\x1B') { continue; - if (!Eat()) + } + if (!Eat()) { return UNCOMPLETED; - if (Current() != '\\') + } + if (Current() != '\\') { continue; + } return SPECIAL; } } -TerminalInputParser::Output TerminalInputParser::ParseMouse( +TerminalInputParser::Output TerminalInputParser::ParseMouse( // NOLINT bool altered, bool pressed, std::vector arguments) { - if (arguments.size() != 3) + if (arguments.size() != 3) { return SPECIAL; + } (void)altered; Output output(MOUSE); - output.mouse.button = Mouse::Button((arguments[0] & 3) + // - ((arguments[0] & 64) >> 4)); - output.mouse.motion = Mouse::Motion(pressed); - output.mouse.shift = bool(arguments[0] & 4); - output.mouse.meta = bool(arguments[0] & 8); - output.mouse.x = arguments[1]; - output.mouse.y = arguments[2]; + output.mouse.button = Mouse::Button((arguments[0] & 3) + // NOLINT + ((arguments[0] & 64) >> 4)); // NOLINT + output.mouse.motion = Mouse::Motion(pressed); // NOLINT + output.mouse.shift = bool(arguments[0] & 4); // NOLINT + output.mouse.meta = bool(arguments[0] & 8); // NOLINT + output.mouse.x = arguments[1]; // NOLINT + output.mouse.y = arguments[2]; // NOLINT return output; } +// NOLINTNEXTLINE TerminalInputParser::Output TerminalInputParser::ParseCursorReporting( std::vector arguments) { - if (arguments.size() != 2) + if (arguments.size() != 2) { return SPECIAL; + } Output output(CURSOR_REPORTING); - output.cursor.y = arguments[0]; - output.cursor.x = arguments[1]; + output.cursor.y = arguments[0]; // NOLINT + output.cursor.x = arguments[1]; // NOLINT return output; } diff --git a/src/ftxui/component/terminal_input_parser.hpp b/src/ftxui/component/terminal_input_parser.hpp index 772631bd8..5449b1e40 100644 --- a/src/ftxui/component/terminal_input_parser.hpp +++ b/src/ftxui/component/terminal_input_parser.hpp @@ -48,7 +48,7 @@ class TerminalInputParser { Output(Type t) : type(t) {} }; - void Send(Output type); + void Send(Output output); Output Parse(); Output ParseUTF8(); Output ParseESC(); diff --git a/src/ftxui/component/util.cpp b/src/ftxui/component/util.cpp index 6175fef6a..246a469e7 100644 --- a/src/ftxui/component/util.cpp +++ b/src/ftxui/component/util.cpp @@ -5,21 +5,25 @@ namespace ftxui { +// NOLINTNEXTLINE Component operator|(Component component, ComponentDecorator decorator) { - return decorator(component); + return decorator(component); // NOLINT } +// NOLINTNEXTLINE Component operator|(Component component, ElementDecorator decorator) { - return component | Renderer(decorator); + return component | Renderer(decorator); // NOLINT } +// NOLINTNEXTLINE Component& operator|=(Component& component, ComponentDecorator decorator) { - component = component | decorator; + component = component | decorator; // NOLINT return component; } +// NOLINTNEXTLINE Component& operator|=(Component& component, ElementDecorator decorator) { - component = component | decorator; + component = component | decorator; // NOLINT return component; } diff --git a/src/ftxui/dom/border.cpp b/src/ftxui/dom/border.cpp index 236c3b8d6..1c8555d24 100644 --- a/src/ftxui/dom/border.cpp +++ b/src/ftxui/dom/border.cpp @@ -1,9 +1,9 @@ #include // for max -#include // for begin, end +#include // for array #include // for allocator, make_shared, __shared_ptr_access -#include // for string, basic_string +#include // for basic_string, string #include // for move -#include // for vector, __alloc_traits<>::value_type +#include // for __alloc_traits<>::value_type #include "ftxui/dom/elements.hpp" // for unpack, Element, Decorator, BorderStyle, ROUNDED, Elements, DOUBLE, EMPTY, HEAVY, LIGHT, border, borderDouble, borderEmpty, borderHeavy, borderLight, borderRounded, borderStyled, borderWith, window #include "ftxui/dom/node.hpp" // for Node, Elements @@ -13,30 +13,25 @@ namespace ftxui { -static std::string simple_border_charset[6][6] = { - {"┌", "┐", "└", "┘", "─", "│"}, // - {"┏", "┓", "┗", "┛", "━", "┃"}, // - {"╔", "╗", "╚", "╝", "═", "║"}, // - {"╭", "╮", "╰", "╯", "─", "│"}, // - {" ", " ", " ", " ", " ", " "}, // +using Charset = std::array; // NOLINT +using Charsets = std::array; // NOLINT +static Charsets simple_border_charset = // NOLINT + { + Charset{"┌", "┐", "└", "┘", "─", "│"}, + Charset{"┏", "┓", "┗", "┛", "━", "┃"}, + Charset{"╔", "╗", "╚", "╝", "═", "║"}, + Charset{"╭", "╮", "╰", "╯", "─", "│"}, + Charset{" ", " ", " ", " ", " ", " "}, }; // For reference, here is the charset for normal border: -// {"┌", "┐", "└", "┘", "─", "│", "┬", "┴", "┤", "├"}; -// TODO(arthursonzogni): Consider adding options to choose the kind of borders -// to use. - class Border : public Node { public: Border(Elements children, BorderStyle style) : Node(std::move(children)), - charset(std::begin(simple_border_charset[style]), - std::end(simple_border_charset[style])) {} - Border(Elements children, Pixel pixel) - : Node(std::move(children)), charset_pixel(10, pixel) {} + charset_(simple_border_charset[style]) {} // NOLINT - std::vector charset_pixel; - std::vector charset; + const Charset& charset_; // NOLINT void ComputeRequirement() override { Node::ComputeRequirement(); @@ -75,63 +70,101 @@ class Border : public Node { children_[0]->Render(screen); // Draw the border. - if (box_.x_min >= box_.x_max || box_.y_min >= box_.y_max) + if (box_.x_min >= box_.x_max || box_.y_min >= box_.y_max) { return; + } - if (!charset.empty()) - RenderPixel(screen); - else - RenderChar(screen); - } - - void RenderPixel(Screen& screen) { - screen.at(box_.x_min, box_.y_min) = charset[0]; - screen.at(box_.x_max, box_.y_min) = charset[1]; - screen.at(box_.x_min, box_.y_max) = charset[2]; - screen.at(box_.x_max, box_.y_max) = charset[3]; + screen.at(box_.x_min, box_.y_min) = charset_[0]; // NOLINT + screen.at(box_.x_max, box_.y_min) = charset_[1]; // NOLINT + screen.at(box_.x_min, box_.y_max) = charset_[2]; // NOLINT + screen.at(box_.x_max, box_.y_max) = charset_[3]; // NOLINT - for (float x = box_.x_min + 1; x < box_.x_max; ++x) { + for (int x = box_.x_min + 1; x < box_.x_max; ++x) { Pixel& p1 = screen.PixelAt(x, box_.y_min); Pixel& p2 = screen.PixelAt(x, box_.y_max); - p1.character = charset[4]; - p2.character = charset[4]; + p1.character = charset_[4]; // NOLINT + p2.character = charset_[4]; // NOLINT p1.automerge = true; p2.automerge = true; } - for (float y = box_.y_min + 1; y < box_.y_max; ++y) { + for (int y = box_.y_min + 1; y < box_.y_max; ++y) { Pixel& p3 = screen.PixelAt(box_.x_min, y); Pixel& p4 = screen.PixelAt(box_.x_max, y); - p3.character = charset[5]; - p4.character = charset[5]; + p3.character = charset_[5]; // NOLINT + p4.character = charset_[5]; // NOLINT p3.automerge = true; p4.automerge = true; } // Draw title. - if (children_.size() == 2) + if (children_.size() == 2) { children_[1]->Render(screen); + } } +}; - void RenderChar(Screen& screen) { - screen.PixelAt(box_.x_min, box_.y_min) = charset_pixel[0]; - screen.PixelAt(box_.x_max, box_.y_min) = charset_pixel[1]; - screen.PixelAt(box_.x_min, box_.y_max) = charset_pixel[2]; - screen.PixelAt(box_.x_max, box_.y_max) = charset_pixel[3]; - for (float x = box_.x_min + 1; x < box_.x_max; ++x) { - Pixel& p1 = screen.PixelAt(x, box_.y_min); - Pixel& p2 = screen.PixelAt(x, box_.y_max); - p1 = charset_pixel[5]; - p2 = charset_pixel[5]; - p1.automerge = true; - p2.automerge = true; +// For reference, here is the charset for normal border: +class BorderPixel : public Node { + public: + BorderPixel(Elements children, Pixel pixel) + : Node(std::move(children)), pixel_(std::move(pixel)) {} + + private: + Pixel pixel_; + + void ComputeRequirement() override { + Node::ComputeRequirement(); + requirement_ = children_[0]->requirement(); + requirement_.min_x += 2; + requirement_.min_y += 2; + if (children_.size() == 2) { + requirement_.min_x = + std::max(requirement_.min_x, children_[1]->requirement().min_x + 2); } - for (float y = box_.y_min + 1; y < box_.y_max; ++y) { - Pixel& p3 = screen.PixelAt(box_.x_min, y); - Pixel& p4 = screen.PixelAt(box_.x_max, y); - p3 = charset_pixel[5]; - p4 = charset_pixel[5]; - p3.automerge = true; - p4.automerge = true; + requirement_.selected_box.x_min++; + requirement_.selected_box.x_max++; + requirement_.selected_box.y_min++; + requirement_.selected_box.y_max++; + } + + void SetBox(Box box) override { + Node::SetBox(box); + if (children_.size() == 2) { + Box title_box; + title_box.x_min = box.x_min + 1; + title_box.x_max = box.x_max - 1; + title_box.y_min = box.y_min; + title_box.y_max = box.y_min; + children_[1]->SetBox(title_box); + } + box.x_min++; + box.x_max--; + box.y_min++; + box.y_max--; + children_[0]->SetBox(box); + } + + void Render(Screen& screen) override { + // Draw content. + children_[0]->Render(screen); + + // Draw the border. + if (box_.x_min >= box_.x_max || box_.y_min >= box_.y_max) { + return; + } + + screen.PixelAt(box_.x_min, box_.y_min) = pixel_; + screen.PixelAt(box_.x_max, box_.y_min) = pixel_; + screen.PixelAt(box_.x_min, box_.y_max) = pixel_; + screen.PixelAt(box_.x_max, box_.y_max) = pixel_; + + for (int x = box_.x_min + 1; x < box_.x_max; ++x) { + screen.PixelAt(x, box_.y_min) = pixel_; + screen.PixelAt(x, box_.y_max) = pixel_; + } + for (int y = box_.y_min + 1; y < box_.y_max; ++y) { + screen.PixelAt(box_.x_min, y) = pixel_; + screen.PixelAt(box_.x_max, y) = pixel_; } } }; @@ -171,9 +204,9 @@ Element border(Element child) { /// @brief Same as border but with a constant Pixel around the element. /// @ingroup dom /// @see border -Decorator borderWith(Pixel pixel) { +Decorator borderWith(const Pixel& pixel) { return [pixel](Element child) { - return std::make_shared(unpack(std::move(child)), pixel); + return std::make_shared(unpack(std::move(child)), pixel); }; } diff --git a/src/ftxui/dom/box_helper.cpp b/src/ftxui/dom/box_helper.cpp index 4fa8fa2e8..32b8f2f4f 100644 --- a/src/ftxui/dom/box_helper.cpp +++ b/src/ftxui/dom/box_helper.cpp @@ -2,8 +2,7 @@ #include // for max -namespace ftxui { -namespace box_helper { +namespace ftxui::box_helper { namespace { // Called when the size allowed is greater than the requested size. This @@ -44,7 +43,7 @@ void ComputeShrinkHard(std::vector* elements, int extra_space, int size) { for (Element& element : *elements) { - if (element.flex_shrink) { + if (element.flex_shrink != 0) { element.size = 0; continue; } @@ -68,23 +67,25 @@ void Compute(std::vector* elements, int target_size) { for (auto& element : *elements) { flex_grow_sum += element.flex_grow; flex_shrink_sum += element.min_size * element.flex_shrink; - if (element.flex_shrink) + if (element.flex_shrink != 0) { flex_shrink_size += element.min_size; + } size += element.min_size; } int extra_space = target_size - size; - if (extra_space >= 0) + if (extra_space >= 0) { ComputeGrow(elements, extra_space, flex_grow_sum); - else if (flex_shrink_size + extra_space >= 0) + } else if (flex_shrink_size + extra_space >= 0) { ComputeShrinkEasy(elements, extra_space, flex_shrink_sum); - else + + } else { ComputeShrinkHard(elements, extra_space + flex_shrink_size, size - flex_shrink_size); + } } -} // namespace box_helper -} // namespace ftxui +} // namespace ftxui::box_helper // Copyright 2021 Arthur Sonzogni. All rights reserved. // Use of this source code is governed by the MIT license that can be found in diff --git a/src/ftxui/dom/canvas.cpp b/src/ftxui/dom/canvas.cpp index c031ab678..0917786db 100644 --- a/src/ftxui/dom/canvas.cpp +++ b/src/ftxui/dom/canvas.cpp @@ -1,8 +1,8 @@ #include "ftxui/dom/canvas.hpp" -#include // for abs #include // for max, min #include // for uint8_t +#include // for abs #include // for allocator, map #include // for make_shared #include // for move, pair @@ -42,26 +42,29 @@ namespace { // 11100010 10100000 10100000 // dot6 // 11100010 10100010 10000000 // dot0-2 +// NOLINTNEXTLINE uint8_t g_map_braille[2][4][2] = { { - {0b00000000, 0b00000001}, // dot1 - {0b00000000, 0b00000010}, // dot2 - {0b00000000, 0b00000100}, // dot3 - {0b00000001, 0b00000000}, // dot0-1 + {0b00000000, 0b00000001}, // NOLINT | dot1 + {0b00000000, 0b00000010}, // NOLINT | dot2 + {0b00000000, 0b00000100}, // NOLINT | dot3 + {0b00000001, 0b00000000}, // NOLINT | dot0-1 }, { - {0b00000000, 0b00001000}, // dot4 - {0b00000000, 0b00010000}, // dot5 - {0b00000000, 0b00100000}, // dot6 - {0b00000010, 0b00000000}, // dot0-2 + {0b00000000, 0b00001000}, // NOLINT | dot4 + {0b00000000, 0b00010000}, // NOLINT | dot5 + {0b00000000, 0b00100000}, // NOLINT | dot6 + {0b00000010, 0b00000000}, // NOLINT | dot0-2 }, }; +// NOLINTNEXTLINE std::vector g_map_block = { " ", "▘", "▖", "▌", "▝", "▀", "▞", "▛", "▗", "▚", "▄", "▙", "▐", "▜", "▟", "█", }; +// NOLINTNEXTLINE const std::map g_map_block_inversed = { {" ", 0b0000}, {"▘", 0b0001}, {"▖", 0b0010}, {"▌", 0b0011}, {"▝", 0b0100}, {"▀", 0b0101}, {"▞", 0b0110}, {"▛", 0b0111}, @@ -69,13 +72,17 @@ const std::map g_map_block_inversed = { {"▐", 0b1100}, {"▜", 0b1101}, {"▟", 0b1110}, {"█", 0b1111}, }; +constexpr auto nostyle = [](Pixel& /*pixel*/) {}; + } // namespace /// @brief Constructor. /// @param width the width of the canvas. A cell is a 2x8 braille dot. /// @param height the height of the canvas. A cell is a 2x8 braille dot. Canvas::Canvas(int width, int height) - : width_(width), height_(height), storage_(width_ * height_ / 8) {} + : width_(width), + height_(height), + storage_(width_ * height_ / 8 /* NOLINT */) {} /// @brief Get the content of a cell. /// @param x the x coordinate of the cell. @@ -90,7 +97,7 @@ Pixel Canvas::GetPixel(int x, int y) const { /// @param y the y coordinate of the dot. /// @param value whether the dot is filled or not. void Canvas::DrawPoint(int x, int y, bool value) { - DrawPoint(x, y, value, [](Pixel&) {}); + DrawPoint(x, y, value, [](Pixel& /*pixel*/) {}); } /// @brief Draw a braille dot. @@ -109,42 +116,45 @@ void Canvas::DrawPoint(int x, int y, bool value, const Color& color) { /// @param style the style of the cell. void Canvas::DrawPoint(int x, int y, bool value, const Stylizer& style) { Style(x, y, style); - if (value) + if (value) { DrawPointOn(x, y); - else + } else { DrawPointOff(x, y); + } } /// @brief Draw a braille dot. /// @param x the x coordinate of the dot. /// @param y the y coordinate of the dot. void Canvas::DrawPointOn(int x, int y) { - if (!IsIn(x, y)) + if (!IsIn(x, y)) { return; + } Cell& cell = storage_[XY{x / 2, y / 4}]; if (cell.type != CellType::kBraille) { cell.content.character = "⠀"; // 3 bytes. cell.type = CellType::kBraille; } - cell.content.character[1] |= g_map_braille[x % 2][y % 4][0]; - cell.content.character[2] |= g_map_braille[x % 2][y % 4][1]; + cell.content.character[1] |= g_map_braille[x % 2][y % 4][0]; // NOLINT + cell.content.character[2] |= g_map_braille[x % 2][y % 4][1]; // NOLINT } /// @brief Erase a braille dot. /// @param x the x coordinate of the dot. /// @param y the y coordinate of the dot. void Canvas::DrawPointOff(int x, int y) { - if (!IsIn(x, y)) + if (!IsIn(x, y)) { return; + } Cell& cell = storage_[XY{x / 2, y / 4}]; if (cell.type != CellType::kBraille) { cell.content.character = "⠀"; // 3 byt cell.type = CellType::kBraille; } - cell.content.character[1] &= ~(g_map_braille[x % 2][y % 4][0]); - cell.content.character[2] &= ~(g_map_braille[x % 2][y % 4][1]); + cell.content.character[1] &= ~(g_map_braille[x % 2][y % 4][0]); // NOLINT + cell.content.character[2] &= ~(g_map_braille[x % 2][y % 4][1]); // NOLINT } /// @brief Toggle a braille dot. A filled one will be erased, and the other will @@ -152,16 +162,17 @@ void Canvas::DrawPointOff(int x, int y) { /// @param x the x coordinate of the dot. /// @param y the y coordinate of the dot. void Canvas::DrawPointToggle(int x, int y) { - if (!IsIn(x, y)) + if (!IsIn(x, y)) { return; + } Cell& cell = storage_[XY{x / 2, y / 4}]; if (cell.type != CellType::kBraille) { cell.content.character = "⠀"; // 3 byt cell.type = CellType::kBraille; } - cell.content.character[1] ^= g_map_braille[x % 2][y % 4][0]; - cell.content.character[2] ^= g_map_braille[x % 2][y % 4][1]; + cell.content.character[1] ^= g_map_braille[x % 2][y % 4][0]; // NOLINT + cell.content.character[2] ^= g_map_braille[x % 2][y % 4][1]; // NOLINT } /// @brief Draw a line made of braille dots. @@ -170,7 +181,7 @@ void Canvas::DrawPointToggle(int x, int y) { /// @param x2 the x coordinate of the second dot. /// @param y2 the y coordinate of the second dot. void Canvas::DrawPointLine(int x1, int y1, int x2, int y2) { - DrawPointLine(x1, y1, x2, y2, [](Pixel&) {}); + DrawPointLine(x1, y1, x2, y2, [](Pixel& /*pixel*/) {}); } /// @brief Draw a line made of braille dots. @@ -201,10 +212,12 @@ void Canvas::DrawPointLine(int x1, const int sy = y1 < y2 ? 1 : -1; const int length = std::max(dx, dy); - if (!IsIn(x1, y1) && !IsIn(x2, y2)) + if (!IsIn(x1, y1) && !IsIn(x2, y2)) { return; - if (dx + dx > width_ * height_) + } + if (dx + dx > width_ * height_) { return; + } int error = dx - dy; for (int i = 0; i < length; ++i) { @@ -226,7 +239,7 @@ void Canvas::DrawPointLine(int x1, /// @param y the y coordinate of the center of the circle. /// @param radius the radius of the circle. void Canvas::DrawPointCircle(int x, int y, int radius) { - DrawPointCircle(x, y, radius, [](Pixel&) {}); + DrawPointCircle(x, y, radius, [](Pixel& /*pixel*/) {}); } /// @brief Draw a circle made of braille dots. @@ -253,7 +266,7 @@ void Canvas::DrawPointCircle(int x, int y, int radius, const Stylizer& style) { /// @param y the y coordinate of the center of the circle. /// @param radius the radius of the circle. void Canvas::DrawPointCircleFilled(int x, int y, int radius) { - DrawPointCircleFilled(x, y, radius, [](Pixel&) {}); + DrawPointCircleFilled(x, y, radius, [](Pixel& /*pixel*/) {}); } /// @brief Draw a filled circle made of braille dots. @@ -287,7 +300,7 @@ void Canvas::DrawPointCircleFilled(int x, /// @param r1 the radius of the ellipse along the x axis. /// @param r2 the radius of the ellipse along the y axis. void Canvas::DrawPointEllipse(int x, int y, int r1, int r2) { - DrawPointEllipse(x, y, r1, r2, [](Pixel&) {}); + DrawPointEllipse(x, y, r1, r2, [](Pixel& /*pixel*/) {}); } /// @brief Draw an ellipse made of braille dots. @@ -351,7 +364,7 @@ void Canvas::DrawPointEllipse(int x1, /// @param r1 the radius of the ellipse along the x axis. /// @param r2 the radius of the ellipse along the y axis. void Canvas::DrawPointEllipseFilled(int x1, int y1, int r1, int r2) { - DrawPointEllipseFilled(x1, y1, r1, r2, [](Pixel&) {}); + DrawPointEllipseFilled(x1, y1, r1, r2, [](Pixel& /*pixel*/) {}); } /// @brief Draw a filled ellipse made of braille dots. @@ -395,11 +408,11 @@ void Canvas::DrawPointEllipseFilled(int x1, e2 = 2 * err; if (e2 >= dx) { x++; - err += dx += 2 * (long)r2 * r2; + err += dx += 2 * (long)r2 * r2; // NOLINT } if (e2 <= dy) { y++; - err += dy += 2 * (long)r1 * r1; + err += dy += 2 * (long)r1 * r1; // NOLINT } } while (x <= 0); @@ -415,7 +428,7 @@ void Canvas::DrawPointEllipseFilled(int x1, /// @param y the y coordinate of the block. /// @param value whether the block is filled or not. void Canvas::DrawBlock(int x, int y, bool value) { - DrawBlock(x, y, value, [](Pixel&) {}); + DrawBlock(x, y, value, [](Pixel& /*pixel*/) {}); } /// @brief Draw a block. @@ -434,18 +447,20 @@ void Canvas::DrawBlock(int x, int y, bool value, const Color& color) { /// @param style the style of the block. void Canvas::DrawBlock(int x, int y, bool value, const Stylizer& style) { Style(x, y, style); - if (value) + if (value) { DrawBlockOn(x, y); - else + } else { DrawBlockOff(x, y); + } } /// @brief Draw a block. /// @param x the x coordinate of the block. /// @param y the y coordinate of the block. void Canvas::DrawBlockOn(int x, int y) { - if (!IsIn(x, y)) + if (!IsIn(x, y)) { return; + } y /= 2; Cell& cell = storage_[XY{x / 2, y / 2}]; if (cell.type != CellType::kBlock) { @@ -453,9 +468,9 @@ void Canvas::DrawBlockOn(int x, int y) { cell.type = CellType::kBlock; } - int bit = (x % 2) * 2 + y % 2; + uint8_t bit = (x % 2) * 2 + y % 2; uint8_t value = g_map_block_inversed.at(cell.content.character); - value |= 1 << bit; + value |= 1U << bit; cell.content.character = g_map_block[value]; } @@ -463,8 +478,9 @@ void Canvas::DrawBlockOn(int x, int y) { /// @param x the x coordinate of the block. /// @param y the y coordinate of the block. void Canvas::DrawBlockOff(int x, int y) { - if (!IsIn(x, y)) + if (!IsIn(x, y)) { return; + } Cell& cell = storage_[XY{x / 2, y / 4}]; if (cell.type != CellType::kBlock) { cell.content.character = " "; @@ -472,9 +488,9 @@ void Canvas::DrawBlockOff(int x, int y) { } y /= 2; - int bit = (y % 2) * 2 + x % 2; + uint8_t bit = (y % 2) * 2 + x % 2; uint8_t value = g_map_block_inversed.at(cell.content.character); - value &= ~(1 << bit); + value &= ~(1U << bit); cell.content.character = g_map_block[value]; } @@ -483,8 +499,9 @@ void Canvas::DrawBlockOff(int x, int y) { /// @param x the x coordinate of the block. /// @param y the y coordinate of the block. void Canvas::DrawBlockToggle(int x, int y) { - if (!IsIn(x, y)) + if (!IsIn(x, y)) { return; + } Cell& cell = storage_[XY{x / 2, y / 4}]; if (cell.type != CellType::kBlock) { cell.content.character = " "; @@ -492,9 +509,9 @@ void Canvas::DrawBlockToggle(int x, int y) { } y /= 2; - int bit = (y % 2) * 2 + x % 2; + uint8_t bit = (y % 2) * 2 + x % 2; uint8_t value = g_map_block_inversed.at(cell.content.character); - value ^= 1 << bit; + value ^= 1U << bit; cell.content.character = g_map_block[value]; } @@ -504,7 +521,7 @@ void Canvas::DrawBlockToggle(int x, int y) { /// @param x2 the x coordinate of the second point of the line. /// @param y2 the y coordinate of the second point of the line. void Canvas::DrawBlockLine(int x1, int y1, int x2, int y2) { - DrawBlockLine(x1, y1, x2, y2, [](Pixel&) {}); + DrawBlockLine(x1, y1, x2, y2, [](Pixel& /*pixel*/) {}); } /// @brief Draw a line made of block characters. @@ -538,10 +555,12 @@ void Canvas::DrawBlockLine(int x1, const int sy = y1 < y2 ? 1 : -1; const int length = std::max(dx, dy); - if (!IsIn(x1, y1) && !IsIn(x2, y2)) + if (!IsIn(x1, y1) && !IsIn(x2, y2)) { return; - if (dx + dx > width_ * height_) + } + if (dx + dx > width_ * height_) { return; + } int error = dx - dy; for (int i = 0; i < length; ++i) { @@ -563,7 +582,7 @@ void Canvas::DrawBlockLine(int x1, /// @param y the y coordinate of the center of the circle. /// @param radius the radius of the circle. void Canvas::DrawBlockCircle(int x, int y, int radius) { - DrawBlockCircle(x, y, radius, [](Pixel&) {}); + DrawBlockCircle(x, y, radius, nostyle); } /// @brief Draw a circle made of block characters. @@ -590,7 +609,7 @@ void Canvas::DrawBlockCircle(int x, int y, int radius, const Stylizer& style) { /// @param y the y coordinate of the center of the circle. /// @param radius the radius of the circle. void Canvas::DrawBlockCircleFilled(int x, int y, int radius) { - DrawBlockCircleFilled(x, y, radius, [](Pixel&) {}); + DrawBlockCircleFilled(x, y, radius, nostyle); } /// @brief Draw a filled circle made of block characters. @@ -624,7 +643,7 @@ void Canvas::DrawBlockCircleFilled(int x, /// @param r1 the radius of the ellipse along the x axis. /// @param r2 the radius of the ellipse along the y axis. void Canvas::DrawBlockEllipse(int x, int y, int r1, int r2) { - DrawBlockEllipse(x, y, r1, r2, [](Pixel&) {}); + DrawBlockEllipse(x, y, r1, r2, nostyle); } /// @brief Draw an ellipse made of block characters. @@ -690,7 +709,7 @@ void Canvas::DrawBlockEllipse(int x1, /// @param r1 the radius of the ellipse along the x axis. /// @param r2 the radius of the ellipse along the y axis. void Canvas::DrawBlockEllipseFilled(int x, int y, int r1, int r2) { - DrawBlockEllipseFilled(x, y, r1, r2, [](Pixel&) {}); + DrawBlockEllipseFilled(x, y, r1, r2, nostyle); } /// @brief Draw a filled ellipse made of block characters. @@ -756,7 +775,7 @@ void Canvas::DrawBlockEllipseFilled(int x1, /// @param y the y coordinate of the text. /// @param value the text to draw. void Canvas::DrawText(int x, int y, const std::string& value) { - DrawText(x, y, value, [](Pixel&) {}); + DrawText(x, y, value, nostyle); } /// @brief Draw a piece of text. @@ -781,8 +800,9 @@ void Canvas::DrawText(int x, const std::string& value, const Stylizer& style) { for (const auto& it : Utf8ToGlyphs(value)) { - if (!IsIn(x, y)) + if (!IsIn(x, y)) { continue; + } Cell& cell = storage_[XY{x / 2, y / 4}]; cell.type = CellType::kText; cell.content.character = it; @@ -794,15 +814,16 @@ void Canvas::DrawText(int x, /// @brief Modify a pixel at a given location. /// @param style a function that modifies the pixel. void Canvas::Style(int x, int y, const Stylizer& style) { - if (IsIn(x, y)) + if (IsIn(x, y)) { style(storage_[XY{x / 2, y / 4}].content); + } } namespace { class CanvasNodeBase : public Node { public: - CanvasNodeBase() {} + CanvasNodeBase() = default; void Render(Screen& screen) override { const Canvas& c = canvas(); @@ -824,7 +845,7 @@ class CanvasNodeBase : public Node { Element canvas(ConstRef canvas) { class Impl : public CanvasNodeBase { public: - Impl(ConstRef canvas) : canvas_(canvas) { + explicit Impl(ConstRef canvas) : canvas_(std::move(canvas)) { requirement_.min_x = (canvas_->width() + 1) / 2; requirement_.min_y = (canvas_->height() + 3) / 4; } @@ -869,7 +890,8 @@ Element canvas(int width, int height, std::function fn) { /// @brief Produce an element drawing a canvas. /// @param fn a function drawing the canvas. Element canvas(std::function fn) { - return canvas(12, 12, std::move(fn)); + const int default_dim = 12; + return canvas(default_dim, default_dim, std::move(fn)); } } // namespace ftxui diff --git a/src/ftxui/dom/clear_under.cpp b/src/ftxui/dom/clear_under.cpp index 17bc1ff50..dd1722269 100644 --- a/src/ftxui/dom/clear_under.cpp +++ b/src/ftxui/dom/clear_under.cpp @@ -29,8 +29,8 @@ class ClearUnder : public NodeDecorator { // combinaison with dbox. /// @see ftxui::dbox /// @ingroup dom -Element clear_under(Element child) { - return std::make_shared(std::move(child)); +Element clear_under(Element element) { + return std::make_shared(std::move(element)); } } // namespace ftxui diff --git a/src/ftxui/dom/dbox.cpp b/src/ftxui/dom/dbox.cpp index 9694d1025..4efdb1360 100644 --- a/src/ftxui/dom/dbox.cpp +++ b/src/ftxui/dom/dbox.cpp @@ -12,7 +12,7 @@ namespace ftxui { class DBox : public Node { public: - DBox(Elements children) : Node(std::move(children)) {} + explicit DBox(Elements children) : Node(std::move(children)) {} void ComputeRequirement() override { requirement_.min_x = 0; @@ -38,8 +38,9 @@ class DBox : public Node { void SetBox(Box box) override { Node::SetBox(box); - for (auto& child : children_) + for (auto& child : children_) { child->SetBox(box); + } } }; diff --git a/src/ftxui/dom/flex.cpp b/src/ftxui/dom/flex.cpp index 7ff726372..09d26d3c5 100644 --- a/src/ftxui/dom/flex.cpp +++ b/src/ftxui/dom/flex.cpp @@ -67,7 +67,7 @@ void function_not_flex(Requirement& r) { class Flex : public Node { public: - Flex(FlexFunction f) : f_(f) {} + explicit Flex(FlexFunction f) : f_(f) {} Flex(FlexFunction f, Element child) : Node(unpack(std::move(child))), f_(f) {} void ComputeRequirement() override { requirement_.min_x = 0; @@ -80,8 +80,9 @@ class Flex : public Node { } void SetBox(Box box) override { - if (children_.empty()) + if (children_.empty()) { return; + } children_[0]->SetBox(box); } diff --git a/src/ftxui/dom/flexbox.cpp b/src/ftxui/dom/flexbox.cpp index 884ee145c..0c4bb3a79 100644 --- a/src/ftxui/dom/flexbox.cpp +++ b/src/ftxui/dom/flexbox.cpp @@ -1,5 +1,5 @@ -#include // for size_t #include // for min, max +#include // for size_t #include // for __shared_ptr_access, shared_ptr, allocator_traits<>::value_type, make_shared #include // for move, swap #include // for vector @@ -56,11 +56,12 @@ class Flexbox : public Node { requirement_.flex_grow_x = 1; requirement_.flex_grow_y = 0; - if (IsColumnOriented()) + if (IsColumnOriented()) { std::swap(requirement_.flex_grow_x, requirement_.flex_grow_y); + } } - bool IsColumnOriented() { + bool IsColumnOriented() const { return config_.direction == FlexboxConfig::Direction::Column || config_.direction == FlexboxConfig::Direction::ColumnInversed; } @@ -84,20 +85,21 @@ class Flexbox : public Node { } void ComputeRequirement() override { - for (auto& child : children_) + for (auto& child : children_) { child->ComputeRequirement(); + } flexbox_helper::Global global; global.config = config_normalized_; if (IsColumnOriented()) { - global.size_x = 100000; + global.size_x = 100000; // NOLINT global.size_y = asked_; } else { global.size_x = asked_; - global.size_y = 100000; + global.size_y = 100000; // NOLINT } Layout(global, true); - if (global.blocks.size() == 0) { + if (global.blocks.empty()) { requirement_.min_x = 0; requirement_.min_y = 0; return; @@ -150,18 +152,19 @@ class Flexbox : public Node { } void Check(Status* status) override { - for (auto& child : children_) + for (auto& child : children_) { child->Check(status); + } if (status->iteration == 0) { - asked_ = 6000; + asked_ = 6000; // NOLINT need_iteration_ = true; } status->need_iteration |= need_iteration_; } - int asked_ = 6000; + int asked_ = 6000; // NOLINT bool need_iteration_ = true; const FlexboxConfig config_; const FlexboxConfig config_normalized_; @@ -190,7 +193,7 @@ class Flexbox : public Node { // ) /// ``` Element flexbox(Elements children, FlexboxConfig config) { - return std::make_shared(std::move(children), std::move(config)); + return std::make_shared(std::move(children), config); } /// @brief A container displaying elements in rows from left to right. When diff --git a/src/ftxui/dom/flexbox_helper.cpp b/src/ftxui/dom/flexbox_helper.cpp index 31f2fc622..4bc805115 100644 --- a/src/ftxui/dom/flexbox_helper.cpp +++ b/src/ftxui/dom/flexbox_helper.cpp @@ -1,14 +1,13 @@ #include "ftxui/dom/flexbox_helper.hpp" -#include // for size_t #include // for min, max +#include // for size_t #include // for allocator_traits<>::value_type #include // for swap, move #include "ftxui/dom/box_helper.hpp" // for Element, Compute -namespace ftxui { -namespace flexbox_helper { +namespace ftxui::flexbox_helper { namespace { void SymmetryXY(FlexboxConfig& c) { @@ -92,15 +91,17 @@ void SetX(Global& global, std::vector lines) { box_helper::Element element; element.min_size = block->min_size_x; element.flex_grow = - block->flex_grow_x || global.config.justify_content == - FlexboxConfig::JustifyContent::Stretch; + block->flex_grow_x != 0 || global.config.justify_content == + FlexboxConfig::JustifyContent::Stretch + ? 1 + : 0; element.flex_shrink = block->flex_shrink_x; elements.push_back(element); } box_helper::Compute( &elements, - global.size_x - global.config.gap_x * (line.blocks.size() - 1)); + global.size_x - global.config.gap_x * (int(line.blocks.size()) - 1)); int x = 0; for (size_t i = 0; i < line.blocks.size(); ++i) { @@ -112,6 +113,7 @@ void SetX(Global& global, std::vector lines) { } } +// NOLINTNEXTLINE(readability-function-cognitive-complexity) void SetY(Global& g, std::vector lines) { std::vector elements; for (auto& line : lines) { @@ -127,7 +129,7 @@ void SetY(Global& g, std::vector lines) { } // box_helper::Compute(&elements, g.size_y); - box_helper::Compute(&elements, 10000); + box_helper::Compute(&elements, 10000); // NOLINT // [Align-content] std::vector ys(elements.size()); @@ -140,48 +142,57 @@ void SetY(Global& g, std::vector lines) { int remaining_space = std::max(0, g.size_y - y); switch (g.config.align_content) { case FlexboxConfig::AlignContent::FlexStart: { - } break; + break; + } case FlexboxConfig::AlignContent::FlexEnd: { - for (size_t i = 0; i < ys.size(); ++i) + for (size_t i = 0; i < ys.size(); ++i) { // NOLINT ys[i] += remaining_space; - } break; + } + break; + } case FlexboxConfig::AlignContent::Center: { - for (size_t i = 0; i < ys.size(); ++i) + for (size_t i = 0; i < ys.size(); ++i) { // NOLINT ys[i] += remaining_space / 2; - } break; + } + break; + } case FlexboxConfig::AlignContent::Stretch: { - for (int i = ys.size() - 1; i >= 0; --i) { + for (int i = ys.size() - 1; i >= 0; --i) { // NOLINT int shifted = remaining_space * (i + 0) / (i + 1); ys[i] += shifted; int consumed = remaining_space - shifted; elements[i].size += consumed; remaining_space -= consumed; } - } break; + break; + } case FlexboxConfig::AlignContent::SpaceBetween: { - for (int i = ys.size() - 1; i >= 1; --i) { + for (int i = ys.size() - 1; i >= 1; --i) { // NOLINT ys[i] += remaining_space; remaining_space = remaining_space * (i - 1) / i; } - } break; + break; + } case FlexboxConfig::AlignContent::SpaceAround: { - for (int i = ys.size() - 1; i >= 0; --i) { + for (int i = ys.size() - 1; i >= 0; --i) { // NOLINT ys[i] += remaining_space * (2 * i + 1) / (2 * i + 2); remaining_space = remaining_space * (2 * i) / (2 * i + 2); } - } break; + break; + } case FlexboxConfig::AlignContent::SpaceEvenly: { - for (int i = ys.size() - 1; i >= 0; --i) { + for (int i = ys.size() - 1; i >= 0; --i) { // NOLINT ys[i] += remaining_space * (i + 1) / (i + 2); remaining_space = remaining_space * (i + 1) / (i + 2); } - } break; + break; + } } // [Align items] @@ -189,7 +200,7 @@ void SetY(Global& g, std::vector lines) { auto& element = elements[i]; for (auto* block : lines[i].blocks) { bool stretch = - block->flex_grow_y || + block->flex_grow_y != 0 || g.config.align_content == FlexboxConfig::AlignContent::Stretch; int size = stretch ? element.size : std::min(element.size, block->min_size_y); @@ -197,22 +208,26 @@ void SetY(Global& g, std::vector lines) { case FlexboxConfig::AlignItems::FlexStart: { block->y = ys[i]; block->dim_y = size; - } break; + break; + } case FlexboxConfig::AlignItems::Center: { block->y = ys[i] + (element.size - size) / 2; block->dim_y = size; - } break; + break; + } case FlexboxConfig::AlignItems::FlexEnd: { block->y = ys[i] + element.size - size; block->dim_y = size; - } break; + break; + } case FlexboxConfig::AlignItems::Stretch: { block->y = ys[i]; block->dim_y = element.size; - } break; + break; + } } } } @@ -228,63 +243,74 @@ void JustifyContent(Global& g, std::vector lines) { break; case FlexboxConfig::JustifyContent::FlexEnd: { - for (auto* block : line.blocks) + for (auto* block : line.blocks) { block->x += remaining_space; - } break; + } + break; + } case FlexboxConfig::JustifyContent::Center: { - for (auto* block : line.blocks) + for (auto* block : line.blocks) { block->x += remaining_space / 2; - } break; + } + break; + } case FlexboxConfig::JustifyContent::SpaceBetween: { - for (int i = line.blocks.size() - 1; i >= 1; --i) { + for (int i = (int)line.blocks.size() - 1; i >= 1; --i) { line.blocks[i]->x += remaining_space; remaining_space = remaining_space * (i - 1) / i; } - } break; + break; + } case FlexboxConfig::JustifyContent::SpaceAround: { - for (int i = line.blocks.size() - 1; i >= 0; --i) { + for (int i = (int)line.blocks.size() - 1; i >= 0; --i) { line.blocks[i]->x += remaining_space * (2 * i + 1) / (2 * i + 2); remaining_space = remaining_space * (2 * i) / (2 * i + 2); } - } break; + break; + } case FlexboxConfig::JustifyContent::SpaceEvenly: { - for (int i = line.blocks.size() - 1; i >= 0; --i) { + for (int i = (int)line.blocks.size() - 1; i >= 0; --i) { line.blocks[i]->x += remaining_space * (i + 1) / (i + 2); remaining_space = remaining_space * (i + 1) / (i + 2); } - } break; + break; + } } } } } // namespace -void Compute(Global& global) { - if (global.config.direction == FlexboxConfig::Direction::Column || - global.config.direction == FlexboxConfig::Direction::ColumnInversed) { - SymmetryXY(global); - Compute(global); - SymmetryXY(global); - return; - } +namespace { +void Compute1(Global& global); +void Compute2(Global& global); +void Compute3(Global& global); + +void Compute1(Global& global) { if (global.config.direction == FlexboxConfig::Direction::RowInversed) { SymmetryX(global); - Compute(global); + Compute2(global); SymmetryX(global); return; } + Compute2(global); +} +void Compute2(Global& global) { if (global.config.wrap == FlexboxConfig::Wrap::WrapInversed) { SymmetryY(global); - Compute(global); + Compute3(global); SymmetryY(global); return; } + Compute3(global); +} +void Compute3(Global& global) { // Step 1: Lay out every elements into rows: std::vector lines; { @@ -295,18 +321,20 @@ void Compute(Global& global) { // No? Then we need to start a new one: if (x + block.min_size_x > global.size_x) { x = 0; - if (!line.blocks.empty()) + if (!line.blocks.empty()) { lines.push_back(std::move(line)); + } line = Line(); } - block.line = lines.size(); - block.line_position = line.blocks.size(); + block.line = (int)lines.size(); + block.line_position = (int)line.blocks.size(); line.blocks.push_back(&block); x += block.min_size_x + global.config.gap_x; } - if (!line.blocks.empty()) + if (!line.blocks.empty()) { lines.push_back(std::move(line)); + } } // Step 2: Set positions on the X axis. @@ -317,8 +345,21 @@ void Compute(Global& global) { SetY(global, lines); } -} // namespace flexbox_helper -} // namespace ftxui +} // namespace + +void Compute(Global& global) { + if (global.config.direction == FlexboxConfig::Direction::Column || + global.config.direction == FlexboxConfig::Direction::ColumnInversed) { + SymmetryXY(global); + Compute1(global); + SymmetryXY(global); + return; + } + Compute1(global); +} + + +} // namespace ftxui::flexbox_helper // Copyright 2021 Arthur Sonzogni. All rights reserved. // Use of this source code is governed by the MIT license that can be found in diff --git a/src/ftxui/dom/focus.cpp b/src/ftxui/dom/focus.cpp index 1dffb4ee5..dbc6d9712 100644 --- a/src/ftxui/dom/focus.cpp +++ b/src/ftxui/dom/focus.cpp @@ -29,17 +29,17 @@ Decorator focusPositionRelative(float x, float y) { class Impl : public NodeDecorator { public: Impl(Element child, float x, float y) - : NodeDecorator(child), x_(x), y_(y) {} + : NodeDecorator(std::move(child)), x_(x), y_(y) {} void ComputeRequirement() override { NodeDecorator::ComputeRequirement(); requirement_.selection = Requirement::Selection::NORMAL; Box& box = requirement_.selected_box; - box.x_min = requirement_.min_x * x_; - box.y_min = requirement_.min_y * y_; - box.x_max = requirement_.min_x * x_; - box.y_max = requirement_.min_y * y_; + box.x_min = (int)((float)requirement_.min_x * x_); + box.y_min = (int)((float)requirement_.min_y * y_); + box.x_max = (int)((float)requirement_.min_x * x_); + box.y_max = (int)((float)requirement_.min_y * y_); } private: @@ -67,8 +67,8 @@ Decorator focusPositionRelative(float x, float y) { Decorator focusPosition(int x, int y) { class Impl : public NodeDecorator { public: - Impl(Element child, float x, float y) - : NodeDecorator(child), x_(x), y_(y) {} + Impl(Element child, int x, int y) + : NodeDecorator(std::move(child)), x_(x), y_(y) {} void ComputeRequirement() override { NodeDecorator::ComputeRequirement(); diff --git a/src/ftxui/dom/frame.cpp b/src/ftxui/dom/frame.cpp index 4215ba556..b67c7bb54 100644 --- a/src/ftxui/dom/frame.cpp +++ b/src/ftxui/dom/frame.cpp @@ -16,7 +16,7 @@ namespace ftxui { class Select : public Node { public: - Select(Elements children) : Node(std::move(children)) {} + explicit Select(Elements children) : Node(std::move(children)) {} void ComputeRequirement() override { Node::ComputeRequirement(); diff --git a/src/ftxui/dom/gauge.cpp b/src/ftxui/dom/gauge.cpp index d00ab0369..81cb82fd9 100644 --- a/src/ftxui/dom/gauge.cpp +++ b/src/ftxui/dom/gauge.cpp @@ -1,17 +1,16 @@ -#include -#include // for max, min -#include // for allocator, make_shared -#include // for string +#include // for allocator, make_shared +#include // for string -#include "ftxui/dom/elements.hpp" // for Element, gauge -#include "ftxui/dom/node.hpp" // for Node +#include "ftxui/dom/elements.hpp" // for GaugeDirection, Element, GaugeDirection::Down, GaugeDirection::Left, GaugeDirection::Right, GaugeDirection::Up, gauge, gaugeDirection, gaugeDown, gaugeLeft, gaugeRight, gaugeUp +#include "ftxui/dom/node.hpp" // for Node #include "ftxui/dom/requirement.hpp" // for Requirement #include "ftxui/screen/box.hpp" // for Box -#include "ftxui/screen/screen.hpp" // for Screen +#include "ftxui/screen/screen.hpp" // for Screen, Pixel namespace ftxui { -static std::string charset_horizontal[11] = { +// NOLINTNEXTLINE +static const std::string charset_horizontal[11] = { #if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK) // Microsoft's terminals often use fonts not handling the 8 unicode // characters for representing the whole gauge. Fallback with less. @@ -23,7 +22,8 @@ static std::string charset_horizontal[11] = { // int(9 * (limit - limit_int) = 9 "█"}; -static std::string charset_vertical[10] = { +// NOLINTNEXTLINE +static const std::string charset_vertical[10] = { "█", "▇", "▆", @@ -43,10 +43,12 @@ class Gauge : public Node { Gauge(float progress, GaugeDirection direction) : progress_(progress), direction_(direction) { // This handle NAN correctly: - if (!(progress_ > 0.f)) - progress_ = 0.f; - if (!(progress_ < 1.f)) - progress_ = 1.f; + if (!(progress_ > 0.F)) { + progress_ = 0.F; + } + if (!(progress_ < 1.F)) { + progress_ = 1.F; + } } void ComputeRequirement() override { @@ -89,49 +91,61 @@ class Gauge : public Node { void RenderHorizontal(Screen& screen, bool invert) { int y = box_.y_min; - if (y > box_.y_max) + if (y > box_.y_max) { return; + } // Draw the progress bar horizontally. { - float progress = invert ? 1.f - progress_ : progress_; - float limit = box_.x_min + progress * (box_.x_max - box_.x_min + 1); - int limit_int = limit; + float progress = invert ? 1.F - progress_ : progress_; + float limit = + (float)box_.x_min + progress * (float)(box_.x_max - box_.x_min + 1); + int limit_int = (int)limit; int x = box_.x_min; - while (x < limit_int) - screen.at(x++, y) = charset_horizontal[9]; + while (x < limit_int) { + screen.at(x++, y) = charset_horizontal[9]; // NOLINT + } + // NOLINTNEXTLINE screen.at(x++, y) = charset_horizontal[int(9 * (limit - limit_int))]; - while (x <= box_.x_max) + while (x <= box_.x_max) { screen.at(x++, y) = charset_horizontal[0]; + } } if (invert) { - for (int x = box_.x_min; x <= box_.x_max; x++) + for (int x = box_.x_min; x <= box_.x_max; x++) { screen.PixelAt(x, y).inverted ^= true; + } } } void RenderVertical(Screen& screen, bool invert) { int x = box_.x_min; - if (x > box_.x_max) + if (x > box_.x_max) { return; + } // Draw the progress bar vertically: { - float progress = invert ? progress_ : 1.f - progress_; - float limit = box_.y_min + progress * (box_.y_max - box_.y_min + 1); - int limit_int = limit; + float progress = invert ? progress_ : 1.F - progress_; + float limit = + (float)box_.y_min + progress * (float)(box_.y_max - box_.y_min + 1); + int limit_int = (int)limit; int y = box_.y_min; - while (y < limit_int) - screen.at(x, y++) = charset_vertical[8]; + while (y < limit_int) { + screen.at(x, y++) = charset_vertical[8]; // NOLINT + } + // NOLINTNEXTLINE screen.at(x, y++) = charset_vertical[int(8 * (limit - limit_int))]; - while (y <= box_.y_max) + while (y <= box_.y_max) { screen.at(x, y++) = charset_vertical[0]; + } } if (invert) { - for (int y = box_.y_min; y <= box_.y_max; y++) + for (int y = box_.y_min; y <= box_.y_max; y++) { screen.PixelAt(x, y).inverted ^= true; + } } } diff --git a/src/ftxui/dom/graph.cpp b/src/ftxui/dom/graph.cpp index 9bd5222f5..015636b11 100644 --- a/src/ftxui/dom/graph.cpp +++ b/src/ftxui/dom/graph.cpp @@ -1,6 +1,7 @@ #include // for function #include // for allocator, make_shared #include // for string +#include // for move #include // for vector #include "ftxui/dom/elements.hpp" // for GraphFunction, Element, graph @@ -11,6 +12,7 @@ namespace ftxui { +// NOLINTNEXTLINE static std::string charset[] = #if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK) // Microsoft's terminals often use fonts not handling the 8 unicode @@ -22,7 +24,8 @@ static std::string charset[] = class Graph : public Node { public: - Graph(GraphFunction graph_function) : graph_function_(graph_function) {} + explicit Graph(GraphFunction graph_function) + : graph_function_(std::move(graph_function)) {} void ComputeRequirement() override { requirement_.flex_grow_x = 1; @@ -43,9 +46,9 @@ class Graph : public Node { int height_2 = 2 * box_.y_max - data[i++]; for (int y = box_.y_min; y <= box_.y_max; ++y) { int yy = 2 * y; - int i_1 = yy < height_1 ? 0 : yy == height_1 ? 3 : 6; - int i_2 = yy < height_2 ? 0 : yy == height_2 ? 1 : 2; - screen.at(x, y) = charset[i_1 + i_2]; + int i_1 = yy < height_1 ? 0 : yy == height_1 ? 3 : 6; // NOLINT + int i_2 = yy < height_2 ? 0 : yy == height_2 ? 1 : 2; // NOLINT + screen.at(x, y) = charset[i_1 + i_2]; // NOLINT } } } @@ -57,7 +60,7 @@ class Graph : public Node { /// @brief Draw a graph using a GraphFunction. /// @param graph_function the function to be called to get the data. Element graph(GraphFunction graph_function) { - return std::make_shared(graph_function); + return std::make_shared(std::move(graph_function)); } } // namespace ftxui diff --git a/src/ftxui/dom/gridbox.cpp b/src/ftxui/dom/gridbox.cpp index fd715121f..9bc21974f 100644 --- a/src/ftxui/dom/gridbox.cpp +++ b/src/ftxui/dom/gridbox.cpp @@ -1,5 +1,5 @@ -#include // for size_t #include // for max, min +#include // for size_t #include // for __shared_ptr_access, shared_ptr, make_shared, allocator_traits<>::value_type #include // for move #include // for vector, __alloc_traits<>::value_type @@ -15,10 +15,11 @@ class Screen; class GridBox : public Node { public: - GridBox(std::vector lines) : Node(), lines_(std::move(lines)) { - y_size = lines_.size(); - for (const auto& line : lines_) + explicit GridBox(std::vector lines) : lines_(std::move(lines)) { + y_size = (int)lines_.size(); + for (const auto& line : lines_) { x_size = std::max(x_size, (int)line.size()); + } for (auto& line : lines_) { while (line.size() < (size_t)x_size) { line.push_back(filler()); @@ -39,8 +40,9 @@ class GridBox : public Node { cell->ComputeRequirement(); // Determine focus based on the focused child. - if (requirement_.selection >= cell->requirement().selection) + if (requirement_.selection >= cell->requirement().selection) { continue; + } requirement_.selection = cell->requirement().selection; requirement_.selected_box = cell->requirement().selected_box; requirement_.selected_box.x_min += requirement_.min_x; @@ -51,16 +53,18 @@ class GridBox : public Node { // Work on the x-axis. for (int x = 0; x < x_size; ++x) { int min_x = 0; - for (int y = 0; y < y_size; ++y) + for (int y = 0; y < y_size; ++y) { min_x = std::max(min_x, lines_[y][x]->requirement().min_x); + } requirement_.min_x += min_x; } // Work on the y-axis. for (int y = 0; y < y_size; ++y) { int min_y = 0; - for (int x = 0; x < x_size; ++x) + for (int x = 0; x < x_size; ++x) { min_y = std::max(min_y, lines_[y][x]->requirement().min_y); + } requirement_.min_y += min_y; } } @@ -70,8 +74,8 @@ class GridBox : public Node { box_helper::Element init; init.min_size = 0; - init.flex_grow = 1024; - init.flex_shrink = 1024; + init.flex_grow = 1024; // NOLINT + init.flex_shrink = 1024; // NOLINT std::vector elements_x(x_size, init); std::vector elements_y(y_size, init); @@ -115,8 +119,9 @@ class GridBox : public Node { void Render(Screen& screen) override { for (auto& line : lines_) { - for (auto& cell : line) + for (auto& cell : line) { cell->Render(screen); + } } } diff --git a/src/ftxui/dom/hbox.cpp b/src/ftxui/dom/hbox.cpp index e75a64c04..75bba74b2 100644 --- a/src/ftxui/dom/hbox.cpp +++ b/src/ftxui/dom/hbox.cpp @@ -1,5 +1,5 @@ -#include // for size_t #include // for max +#include // for size_t #include // for __shared_ptr_access, shared_ptr, make_shared, allocator_traits<>::value_type #include // for move #include // for vector, __alloc_traits<>::value_type @@ -14,7 +14,7 @@ namespace ftxui { class HBox : public Node { public: - HBox(Elements children) : Node(std::move(children)) {} + explicit HBox(Elements children) : Node(std::move(children)) {} void ComputeRequirement() override { requirement_.min_x = 0; diff --git a/src/ftxui/dom/node.cpp b/src/ftxui/dom/node.cpp index fe65823e6..9de54c14c 100644 --- a/src/ftxui/dom/node.cpp +++ b/src/ftxui/dom/node.cpp @@ -5,15 +5,16 @@ namespace ftxui { -Node::Node() {} +Node::Node() = default; Node::Node(Elements children) : children_(std::move(children)) {} -Node::~Node() {} +Node::~Node() = default; /// @brief Compute how much space an elements needs. /// @ingroup dom void Node::ComputeRequirement() { - for (auto& child : children_) + for (auto& child : children_) { child->ComputeRequirement(); + } } /// @brief Assign a position and a dimension to an element for drawing. @@ -25,13 +26,15 @@ void Node::SetBox(Box box) { /// @brief Display an element on a ftxui::Screen. /// @ingroup dom void Node::Render(Screen& screen) { - for (auto& child : children_) + for (auto& child : children_) { child->Render(screen); + } } void Node::Check(Status* status) { - for (auto& child : children_) + for (auto& child : children_) { child->Check(status); + } status->need_iteration |= (status->iteration == 0); } @@ -52,7 +55,8 @@ void Render(Screen& screen, Node* node) { Node::Status status; node->Check(&status); - while (status.need_iteration && status.iteration < 20) { + const int max_iterations = 20; + while (status.need_iteration && status.iteration < max_iterations) { // Step 1: Find what dimension this elements wants to be. node->ComputeRequirement(); diff --git a/src/ftxui/dom/paragraph.cpp b/src/ftxui/dom/paragraph.cpp index 4648a6d97..ab46dfa40 100644 --- a/src/ftxui/dom/paragraph.cpp +++ b/src/ftxui/dom/paragraph.cpp @@ -8,12 +8,13 @@ namespace ftxui { namespace { -Elements Split(std::string the_text) { +Elements Split(const std::string& the_text) { Elements output; std::stringstream ss(the_text); std::string word; - while (std::getline(ss, word, ' ')) + while (std::getline(ss, word, ' ')) { output.push_back(text(word)); + } return output; } } // namespace @@ -21,37 +22,37 @@ Elements Split(std::string the_text) { /// @brief Return an element drawing the paragraph on multiple lines. /// @ingroup dom /// @see flexbox. -Element paragraph(std::string the_text) { - return paragraphAlignLeft(std::move(the_text)); +Element paragraph(const std::string& the_text) { + return paragraphAlignLeft(the_text); } /// @brief Return an element drawing the paragraph on multiple lines, aligned on /// the left. /// @ingroup dom /// @see flexbox. -Element paragraphAlignLeft(std::string the_text) { +Element paragraphAlignLeft(const std::string& the_text) { static const auto config = FlexboxConfig().SetGap(1, 0); - return flexbox(Split(std::move(the_text)), config); + return flexbox(Split(the_text), config); } /// @brief Return an element drawing the paragraph on multiple lines, aligned on /// the right. /// @ingroup dom /// @see flexbox. -Element paragraphAlignRight(std::string the_text) { +Element paragraphAlignRight(const std::string& the_text) { static const auto config = FlexboxConfig().SetGap(1, 0).Set(FlexboxConfig::JustifyContent::FlexEnd); - return flexbox(Split(std::move(the_text)), config); + return flexbox(Split(the_text), config); } /// @brief Return an element drawing the paragraph on multiple lines, aligned on /// the center. /// @ingroup dom /// @see flexbox. -Element paragraphAlignCenter(std::string the_text) { +Element paragraphAlignCenter(const std::string& the_text) { static const auto config = FlexboxConfig().SetGap(1, 0).Set(FlexboxConfig::JustifyContent::Center); - return flexbox(Split(std::move(the_text)), config); + return flexbox(Split(the_text), config); } /// @brief Return an element drawing the paragraph on multiple lines, aligned @@ -59,10 +60,10 @@ Element paragraphAlignCenter(std::string the_text) { /// the center. /// @ingroup dom /// @see flexbox. -Element paragraphAlignJustify(std::string the_text) { +Element paragraphAlignJustify(const std::string& the_text) { static const auto config = FlexboxConfig().SetGap(1, 0).Set( FlexboxConfig::JustifyContent::SpaceBetween); - Elements words = Split(std::move(the_text)); + Elements words = Split(the_text); words.push_back(text("") | xflex); return flexbox(std::move(words), config); } diff --git a/src/ftxui/dom/scroll_indicator.cpp b/src/ftxui/dom/scroll_indicator.cpp index 11001f559..c96fdbb6d 100644 --- a/src/ftxui/dom/scroll_indicator.cpp +++ b/src/ftxui/dom/scroll_indicator.cpp @@ -21,27 +21,29 @@ Element vscroll_indicator(Element child) { using NodeDecorator::NodeDecorator; void ComputeRequirement() override { - Node::ComputeRequirement(); + NodeDecorator::ComputeRequirement(); requirement_ = children_[0]->requirement(); requirement_.min_x++; } void SetBox(Box box) override { - Node::SetBox(box); - if (box_.x_min > box_.x_max) + NodeDecorator::SetBox(box); + if (box_.x_min > box_.x_max) { box_.x_max--; + } children_[0]->SetBox(box); } void Render(Screen& screen) final { - Node::Render(screen); + NodeDecorator::Render(screen); const Box& stencil = screen.stencil; int size_inner = box_.y_max - box_.y_min; int size_outter = stencil.y_max - stencil.y_min + 1; - if (size_outter >= size_inner) + if (size_outter >= size_inner) { return; + } int size = 2 * size_outter * size_outter / size_inner; size = std::max(size, 1); @@ -56,7 +58,7 @@ Element vscroll_indicator(Element child) { bool up = (start_y <= y_up) && (y_up <= start_y + size); bool down = (start_y <= y_down) && (y_down <= start_y + size); - const char* c = up ? (down ? "┃" : "╹") : (down ? "╻" : " "); + const char* c = up ? (down ? "┃" : "╹") : (down ? "╻" : " "); // NOLINT screen.PixelAt(x, y) = Pixel(); screen.PixelAt(x, y).character = c; } diff --git a/src/ftxui/dom/separator.cpp b/src/ftxui/dom/separator.cpp index b668554fa..a6b986d41 100644 --- a/src/ftxui/dom/separator.cpp +++ b/src/ftxui/dom/separator.cpp @@ -1,5 +1,7 @@ -#include // for make_shared, allocator -#include // for string +#include // for array, array<>::value_type +#include // for make_shared, allocator +#include // for basic_string, string +#include // for move #include "ftxui/dom/elements.hpp" // for Element, BorderStyle, LIGHT, separator, DOUBLE, EMPTY, HEAVY, separatorCharacter, separatorDouble, separatorEmpty, separatorHSelector, separatorHeavy, separatorLight, separatorStyled, separatorVSelector #include "ftxui/dom/node.hpp" // for Node @@ -10,19 +12,25 @@ namespace ftxui { +namespace { using ftxui::Screen; -const std::string charset[][2] = { - {"│", "─"}, // - {"┃", "━"}, // - {"║", "═"}, // - {"│", "─"}, // - {" ", " "}, // +using Charset = std::array; // NOLINT +using Charsets = std::array; // NOLINT +const Charsets charsets = // NOLINT + { + Charset{"│", "─"}, // + Charset{"┃", "━"}, // + Charset{"║", "═"}, // + Charset{"│", "─"}, // + Charset{" ", " "}, // }; +} // namespace + class Separator : public Node { public: - Separator(std::string value) : value_(value) {} + explicit Separator(std::string value) : value_(std::move(value)) {} void ComputeRequirement() override { requirement_.min_x = 1; @@ -44,7 +52,7 @@ class Separator : public Node { class SeparatorAuto : public Node { public: - SeparatorAuto(BorderStyle style) : style_(style) {} + explicit SeparatorAuto(BorderStyle style) : style_(style) {} void ComputeRequirement() override { requirement_.min_x = 1; @@ -55,7 +63,7 @@ class SeparatorAuto : public Node { bool is_column = (box_.x_max == box_.x_min); bool is_line = (box_.y_min == box_.y_max); - const std::string c = charset[style_][is_line && !is_column]; + const std::string c = charsets[style_][int(is_line && !is_column)]; for (int y = box_.y_min; y <= box_.y_max; ++y) { for (int x = box_.x_min; x <= box_.x_max; ++x) { @@ -71,7 +79,8 @@ class SeparatorAuto : public Node { class SeparatorWithPixel : public SeparatorAuto { public: - SeparatorWithPixel(Pixel pixel) : SeparatorAuto(LIGHT), pixel_(pixel) { + explicit SeparatorWithPixel(Pixel pixel) + : SeparatorAuto(LIGHT), pixel_(std::move(pixel)) { pixel_.automerge = true; } void Render(Screen& screen) override { @@ -337,7 +346,7 @@ Element separatorEmpty() { /// down /// ``` Element separatorCharacter(std::string value) { - return std::make_shared(value); + return std::make_shared(std::move(value)); } /// @brief Draw a separator in between two element filled with a given pixel. @@ -367,7 +376,7 @@ Element separatorCharacter(std::string value) { /// Down /// ``` Element separator(Pixel pixel) { - return std::make_shared(pixel); + return std::make_shared(std::move(pixel)); } /// @brief Draw an horizontal bar, with the area in between left/right colored @@ -384,27 +393,28 @@ Element separator(Pixel pixel) { /// ``` Element separatorHSelector(float left, float right, - Color selected_color, - Color unselected_color) { + Color unselected_color, + Color selected_color) { class Impl : public Node { public: Impl(float left, float right, Color selected_color, Color unselected_color) : left_(left), right_(right), - selected_color_(selected_color), - unselected_color_(unselected_color) {} + unselected_color_(unselected_color), + selected_color_(selected_color) {} void ComputeRequirement() override { requirement_.min_x = 1; requirement_.min_y = 1; } void Render(Screen& screen) override { - if (box_.y_max < box_.y_min) + if (box_.y_max < box_.y_min) { return; + } // This are the two location with an empty demi-cell. - int demi_cell_left = left_ * 2 - 1; - int demi_cell_right = right_ * 2 + 2; + int demi_cell_left = int(left_ * 2.F - 1.F); // NOLINT + int demi_cell_right = int(right_ * 2.F + 2.F); // NOLINT int y = box_.y_min; for (int x = box_.x_min; x <= box_.x_max; ++x) { @@ -419,23 +429,24 @@ Element separatorHSelector(float left, pixel.character = "─"; pixel.automerge = true; } else { - pixel.character = a_empty ? "╶" : "╴"; + pixel.character = a_empty ? "╶" : "╴"; // NOLINT pixel.automerge = false; } - if (demi_cell_left <= a && b <= demi_cell_right) + if (demi_cell_left <= a && b <= demi_cell_right) { pixel.foreground_color = selected_color_; - else + } else { pixel.foreground_color = unselected_color_; + } } } float left_; float right_; - Color selected_color_; Color unselected_color_; + Color selected_color_; }; - return std::make_shared(left, right, selected_color, unselected_color); + return std::make_shared(left, right, unselected_color, selected_color); } /// @brief Draw an vertical bar, with the area in between up/downcolored @@ -452,27 +463,28 @@ Element separatorHSelector(float left, /// ``` Element separatorVSelector(float up, float down, - Color selected_color, - Color unselected_color) { + Color unselected_color, + Color selected_color) { class Impl : public Node { public: - Impl(float up, float down, Color selected_color, Color unselected_color) + Impl(float up, float down, Color unselected_color, Color selected_color) : up_(up), down_(down), - selected_color_(selected_color), - unselected_color_(unselected_color) {} + unselected_color_(unselected_color), + selected_color_(selected_color) {} void ComputeRequirement() override { requirement_.min_x = 1; requirement_.min_y = 1; } void Render(Screen& screen) override { - if (box_.x_max < box_.x_min) + if (box_.x_max < box_.x_min) { return; + } // This are the two location with an empty demi-cell. - int demi_cell_up = up_ * 2 - 1; - int demi_cell_down = down_ * 2 + 2; + int demi_cell_up = int(up_ * 2 - 1); + int demi_cell_down = int(down_ * 2 + 2); int x = box_.x_min; for (int y = box_.y_min; y <= box_.y_max; ++y) { @@ -487,23 +499,24 @@ Element separatorVSelector(float up, pixel.character = "│"; pixel.automerge = true; } else { - pixel.character = a_empty ? "╷" : "╵"; + pixel.character = a_empty ? "╷" : "╵"; // NOLINT pixel.automerge = false; } - if (demi_cell_up <= a && b <= demi_cell_down) + if (demi_cell_up <= a && b <= demi_cell_down) { pixel.foreground_color = selected_color_; - else + } else { pixel.foreground_color = unselected_color_; + } } } float up_; float down_; - Color selected_color_; Color unselected_color_; + Color selected_color_; }; - return std::make_shared(up, down, selected_color, unselected_color); + return std::make_shared(up, down, unselected_color, selected_color); } } // namespace ftxui diff --git a/src/ftxui/dom/size.cpp b/src/ftxui/dom/size.cpp index 3087dbb3b..bef4ebe5d 100644 --- a/src/ftxui/dom/size.cpp +++ b/src/ftxui/dom/size.cpp @@ -1,4 +1,3 @@ -#include // for size_t #include // for min, max #include // for make_shared, __shared_ptr_access #include // for move @@ -13,7 +12,7 @@ namespace ftxui { class Size : public Node { public: - Size(Element child, Direction direction, Constraint constraint, size_t value) + Size(Element child, Direction direction, Constraint constraint, int value) : Node(unpack(std::move(child))), direction_(direction), constraint_(constraint), diff --git a/src/ftxui/dom/spinner.cpp b/src/ftxui/dom/spinner.cpp index 1bd3033c9..3e7c24021 100644 --- a/src/ftxui/dom/spinner.cpp +++ b/src/ftxui/dom/spinner.cpp @@ -1,14 +1,16 @@ -#include // for size_t -#include // for allocator, allocator_traits<>::value_type -#include // for basic_string, string -#include // for move -#include // for vector, __alloc_traits<>::value_type +#include // for size_t +#include // for allocator, allocator_traits<>::value_type +#include // for basic_string, string +#include // for move +#include // for vector, __alloc_traits<>::value_type #include "ftxui/dom/elements.hpp" // for Element, gauge, text, vbox, spinner namespace ftxui { -static const std::vector>> elements = { +namespace { +// NOLINTNEXTLINE +const std::vector>> elements = { { {"Replaced by the gauge"}, }, @@ -246,6 +248,8 @@ static const std::vector>> elements = { " LOLLOL ", }}}; +} // namespace + /// @brief Useful to represent the effect of time and/or events. This display an /// ASCII art "video". /// @param charset_index The type of "video". @@ -254,16 +258,19 @@ static const std::vector>> elements = { /// @ingroup dom Element spinner(int charset_index, size_t image_index) { if (charset_index == 0) { - image_index %= 40; - if (image_index > 20) - image_index = 40 - image_index; - return gauge(image_index * 0.05); + const int progress_size = 40; + image_index %= progress_size; + if (image_index > progress_size / 2) { + image_index = progress_size - image_index; + } + return gauge(float(image_index) * 0.05F); // NOLINT } - charset_index %= elements.size(); - image_index %= elements[charset_index].size(); + charset_index %= (int)elements.size(); + image_index %= (int)elements[charset_index].size(); std::vector lines; - for (const auto& it : elements[charset_index][image_index]) + for (const auto& it : elements[charset_index][image_index]) { lines.push_back(text(it)); + } return vbox(std::move(lines)); } diff --git a/src/ftxui/dom/table.cpp b/src/ftxui/dom/table.cpp index 200a6c747..d3ec5d0c0 100644 --- a/src/ftxui/dom/table.cpp +++ b/src/ftxui/dom/table.cpp @@ -13,6 +13,7 @@ bool IsCell(int x, int y) { return x % 2 == 1 && y % 2 == 1; } +// NOLINTNEXTLINE static std::string charset[6][6] = { {"┌", "┐", "└", "┘", "─", "│"}, // {"┏", "┓", "┗", "┛", "━", "┃"}, // @@ -29,8 +30,9 @@ int Wrap(int input, int modulo) { } void Order(int& a, int& b) { - if (a >= b) + if (a >= b) { std::swap(a, b); + } } } // namespace @@ -42,10 +44,10 @@ Table::Table() { Table::Table(std::vector> input) { std::vector> output; for (auto& row : input) { - output.push_back({}); + output.emplace_back(); auto& output_row = output.back(); for (auto& cell : row) { - output_row.push_back(text(cell)); + output_row.push_back(text(std::move(cell))); } } Initialize(std::move(output)); @@ -56,18 +58,20 @@ Table::Table(std::vector> input) { } void Table::Initialize(std::vector> input) { - input_dim_y_ = input.size(); + input_dim_y_ = (int)input.size(); input_dim_x_ = 0; - for (auto& row : input) + for (auto& row : input) { input_dim_x_ = std::max(input_dim_x_, (int)row.size()); + } dim_y_ = 2 * input_dim_y_ + 1; dim_x_ = 2 * input_dim_x_ + 1; // Reserve space. elements_.resize(dim_y_); - for (int y = 0; y < dim_y_; ++y) + for (int y = 0; y < dim_y_; ++y) { elements_[y].resize(dim_x_); + } // Transfert elements_ from |input| toward |elements_|. { @@ -88,8 +92,9 @@ void Table::Initialize(std::vector> input) { auto& element = elements_[y][x]; if (IsCell(x, y)) { - if (!element) + if (!element) { element = emptyElement(); + } continue; } @@ -129,7 +134,7 @@ TableSelection Table::SelectRectangle(int column_min, row_max = Wrap(row_max, input_dim_y_); Order(row_min, row_max); - TableSelection output; + TableSelection output; // NOLINT output.table_ = this; output.x_min_ = 2 * column_min; output.x_max_ = 2 * column_max + 2; @@ -139,7 +144,7 @@ TableSelection Table::SelectRectangle(int column_min, } TableSelection Table::SelectAll() { - TableSelection output; + TableSelection output; // NOLINT output.table_ = this; output.x_min_ = 0; output.x_max_ = dim_x_ - 1; @@ -172,6 +177,7 @@ Element Table::Render() { return gridbox(std::move(elements_)); } +// NOLINTNEXTLINE void TableSelection::Decorate(Decorator decorator) { for (int y = y_min_; y <= y_max_; ++y) { for (int x = x_min_; x <= x_max_; ++x) { @@ -181,10 +187,11 @@ void TableSelection::Decorate(Decorator decorator) { } } +// NOLINTNEXTLINE void TableSelection::DecorateCells(Decorator decorator) { for (int y = y_min_; y <= y_max_; ++y) { for (int x = x_min_; x <= x_max_; ++x) { - if (y % 2 && x % 2) { + if (y % 2 == 1 && x % 2 == 1) { Element& e = table_->elements_[y][x]; e = std::move(e) | decorator; } @@ -192,12 +199,13 @@ void TableSelection::DecorateCells(Decorator decorator) { } } +// NOLINTNEXTLINE void TableSelection::DecorateAlternateColumn(Decorator decorator, int modulo, int shift) { for (int y = y_min_; y <= y_max_; ++y) { for (int x = x_min_; x <= x_max_; ++x) { - if (y % 2 && (x / 2) % modulo == shift) { + if (y % 2 == 1 && (x / 2) % modulo == shift) { Element& e = table_->elements_[y][x]; e = std::move(e) | decorator; } @@ -205,12 +213,13 @@ void TableSelection::DecorateAlternateColumn(Decorator decorator, } } +// NOLINTNEXTLINE void TableSelection::DecorateAlternateRow(Decorator decorator, int modulo, int shift) { for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) { for (int x = x_min_; x <= x_max_; ++x) { - if (y % 2 && (y / 2) % modulo == shift) { + if (y % 2 == 1 && (y / 2) % modulo == shift) { Element& e = table_->elements_[y][x]; e = std::move(e) | decorator; } @@ -218,12 +227,13 @@ void TableSelection::DecorateAlternateRow(Decorator decorator, } } +// NOLINTNEXTLINE void TableSelection::DecorateCellsAlternateColumn(Decorator decorator, int modulo, int shift) { for (int y = y_min_; y <= y_max_; ++y) { for (int x = x_min_; x <= x_max_; ++x) { - if (y % 2 && x % 2 && ((x / 2) % modulo == shift)) { + if (y % 2 == 1 && x % 2 == 1 && ((x / 2) % modulo == shift)) { Element& e = table_->elements_[y][x]; e = std::move(e) | decorator; } @@ -231,12 +241,13 @@ void TableSelection::DecorateCellsAlternateColumn(Decorator decorator, } } +// NOLINTNEXTLINE void TableSelection::DecorateCellsAlternateRow(Decorator decorator, int modulo, int shift) { for (int y = y_min_; y <= y_max_; ++y) { for (int x = x_min_; x <= x_max_; ++x) { - if (y % 2 && x % 2 && ((y / 2) % modulo == shift)) { + if (y % 2 == 1 && x % 2 == 1 && ((y / 2) % modulo == shift)) { Element& e = table_->elements_[y][x]; e = std::move(e) | decorator; } @@ -244,77 +255,82 @@ void TableSelection::DecorateCellsAlternateRow(Decorator decorator, } } -void TableSelection::Border(BorderStyle style) { - BorderLeft(style); - BorderRight(style); - BorderTop(style); - BorderBottom(style); - - table_->elements_[y_min_][x_min_] = text(charset[style][0]) | automerge; - table_->elements_[y_min_][x_max_] = text(charset[style][1]) | automerge; - table_->elements_[y_max_][x_min_] = text(charset[style][2]) | automerge; - table_->elements_[y_max_][x_max_] = text(charset[style][3]) | automerge; +void TableSelection::Border(BorderStyle border) { + BorderLeft(border); + BorderRight(border); + BorderTop(border); + BorderBottom(border); + + // NOLINTNEXTLINE + table_->elements_[y_min_][x_min_] = text(charset[border][0]) | automerge; + // NOLINTNEXTLINE + table_->elements_[y_min_][x_max_] = text(charset[border][1]) | automerge; + // NOLINTNEXTLINE + table_->elements_[y_max_][x_min_] = text(charset[border][2]) | automerge; + // NOLINTNEXTLINE + table_->elements_[y_max_][x_max_] = text(charset[border][3]) | automerge; } -void TableSelection::Separator(BorderStyle style) { +void TableSelection::Separator(BorderStyle border) { for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) { for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) { if (y % 2 == 0 || x % 2 == 0) { Element& e = table_->elements_[y][x]; - e = (y % 2) ? separatorCharacter(charset[style][5]) | automerge - : separatorCharacter(charset[style][4]) | automerge; + e = (y % 2 == 1) + ? separatorCharacter(charset[border][5]) | automerge // NOLINT + : separatorCharacter(charset[border][4]) | automerge; // NOLINT } } } } -void TableSelection::SeparatorVertical(BorderStyle style) { +void TableSelection::SeparatorVertical(BorderStyle border) { for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) { for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) { if (x % 2 == 0) { table_->elements_[y][x] = - separatorCharacter(charset[style][5]) | automerge; + separatorCharacter(charset[border][5]) | automerge; // NOLINT } } } } -void TableSelection::SeparatorHorizontal(BorderStyle style) { +void TableSelection::SeparatorHorizontal(BorderStyle border) { for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) { for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) { if (y % 2 == 0) { table_->elements_[y][x] = - separatorCharacter(charset[style][4]) | automerge; + separatorCharacter(charset[border][4]) | automerge; // NOLINT } } } } -void TableSelection::BorderLeft(BorderStyle style) { +void TableSelection::BorderLeft(BorderStyle border) { for (int y = y_min_; y <= y_max_; y++) { table_->elements_[y][x_min_] = - separatorCharacter(charset[style][5]) | automerge; + separatorCharacter(charset[border][5]) | automerge; // NOLINT } } -void TableSelection::BorderRight(BorderStyle style) { +void TableSelection::BorderRight(BorderStyle border) { for (int y = y_min_; y <= y_max_; y++) { table_->elements_[y][x_max_] = - separatorCharacter(charset[style][5]) | automerge; + separatorCharacter(charset[border][5]) | automerge; // NOLINT } } -void TableSelection::BorderTop(BorderStyle style) { +void TableSelection::BorderTop(BorderStyle border) { for (int x = x_min_; x <= x_max_; x++) { table_->elements_[y_min_][x] = - separatorCharacter(charset[style][4]) | automerge; + separatorCharacter(charset[border][4]) | automerge; // NOLINT } } -void TableSelection::BorderBottom(BorderStyle style) { +void TableSelection::BorderBottom(BorderStyle border) { for (int x = x_min_; x <= x_max_; x++) { table_->elements_[y_max_][x] = - separatorCharacter(charset[style][4]) | automerge; + separatorCharacter(charset[border][4]) | automerge; // NOLINT } } diff --git a/src/ftxui/dom/text.cpp b/src/ftxui/dom/text.cpp index a785933fc..fde601d38 100644 --- a/src/ftxui/dom/text.cpp +++ b/src/ftxui/dom/text.cpp @@ -1,6 +1,7 @@ #include // for min #include // for make_shared #include // for string, wstring +#include // for move #include // for vector #include "ftxui/dom/deprecated.hpp" // for text, vtext @@ -17,7 +18,7 @@ using ftxui::Screen; class Text : public Node { public: - Text(std::string text) : text_(text) {} + explicit Text(std::string text) : text_(std::move(text)) {} void ComputeRequirement() override { requirement_.min_x = string_width(text_); @@ -27,11 +28,13 @@ class Text : public Node { void Render(Screen& screen) override { int x = box_.x_min; int y = box_.y_min; - if (y > box_.y_max) + if (y > box_.y_max) { return; + } for (const auto& cell : Utf8ToGlyphs(text_)) { - if (x > box_.x_max) + if (x > box_.x_max) { return; + } screen.PixelAt(x, y).character = cell; ++x; } @@ -43,8 +46,8 @@ class Text : public Node { class VText : public Node { public: - VText(std::string text) - : text_(text), width_{std::min(string_width(text_), 1)} {} + explicit VText(std::string text) + : text_(std::move(text)), width_{std::min(string_width(text_), 1)} {} void ComputeRequirement() override { requirement_.min_x = width_; @@ -54,11 +57,13 @@ class VText : public Node { void Render(Screen& screen) override { int x = box_.x_min; int y = box_.y_min; - if (x + width_ - 1 > box_.x_max) + if (x + width_ - 1 > box_.x_max) { return; + } for (const auto& it : Utf8ToGlyphs(text_)) { - if (y > box_.y_max) + if (y > box_.y_max) { return; + } screen.PixelAt(x, y).character = it; y += 1; } @@ -85,7 +90,7 @@ class VText : public Node { /// Hello world! /// ``` Element text(std::string text) { - return std::make_shared(text); + return std::make_shared(std::move(text)); } /// @brief Display a piece of unicode text. @@ -103,7 +108,7 @@ Element text(std::string text) { /// ```bash /// Hello world! /// ``` -Element text(std::wstring text) { +Element text(std::wstring text) { // NOLINT return std::make_shared(to_string(text)); } @@ -134,7 +139,7 @@ Element text(std::wstring text) { /// ! /// ``` Element vtext(std::string text) { - return std::make_shared(text); + return std::make_shared(std::move(text)); } /// @brief Display a piece unicode text vertically. @@ -163,7 +168,7 @@ Element vtext(std::string text) { /// d /// ! /// ``` -Element vtext(std::wstring text) { +Element vtext(std::wstring text) { // NOLINT return std::make_shared(to_string(text)); } diff --git a/src/ftxui/dom/util.cpp b/src/ftxui/dom/util.cpp index 39df1fd6f..adf6be382 100644 --- a/src/ftxui/dom/util.cpp +++ b/src/ftxui/dom/util.cpp @@ -36,16 +36,18 @@ Element nothing(Element element) { /// auto decorator = bold | blink; /// ``` Decorator operator|(Decorator a, Decorator b) { - return compose(a, b); + return compose(std::move(a), // + std::move(b)); } /// @brief From a set of element, apply a decorator to every elements. /// @return the set of decorated element. /// @ingroup dom -Elements operator|(Elements elements, Decorator decorator) { +Elements operator|(Elements elements, Decorator decorator) { // NOLINT Elements output; - for (auto& it : elements) + for (auto& it : elements) { output.push_back(std::move(it) | decorator); + } return output; } @@ -62,7 +64,7 @@ Elements operator|(Elements elements, Decorator decorator) { /// ```cpp /// text("Hello") | bold; /// ``` -Element operator|(Element element, Decorator decorator) { +Element operator|(Element element, Decorator decorator) { // NOLINT return decorator(std::move(element)); } @@ -78,7 +80,7 @@ Element operator|(Element element, Decorator decorator) { /// element |= bold; /// ``` Element& operator|=(Element& e, Decorator d) { - e = e | d; + e = e | std::move(d); return e; } @@ -95,7 +97,8 @@ Dimensions Dimension::Fit(Element& e) { Node::Status status; e->Check(&status); - while (status.need_iteration && status.iteration < 20) { + const int max_iteration = 20; + while (status.need_iteration && status.iteration < max_iteration) { e->ComputeRequirement(); // Don't give the element more space than it needs: @@ -107,8 +110,9 @@ Dimensions Dimension::Fit(Element& e) { status.iteration++; e->Check(&status); - if (!status.need_iteration) + if (!status.need_iteration) { break; + } // Increase the size of the box until it fits, but not more than the with of // the terminal emulator: box.x_max = std::min(e->requirement().min_x, fullsize.dimx); diff --git a/src/ftxui/dom/vbox.cpp b/src/ftxui/dom/vbox.cpp index 82417e145..ecd63da31 100644 --- a/src/ftxui/dom/vbox.cpp +++ b/src/ftxui/dom/vbox.cpp @@ -1,5 +1,5 @@ -#include // for size_t #include // for max +#include // for size_t #include // for __shared_ptr_access, shared_ptr, make_shared, allocator_traits<>::value_type #include // for move #include // for vector, __alloc_traits<>::value_type @@ -14,7 +14,7 @@ namespace ftxui { class VBox : public Node { public: - VBox(Elements children) : Node(std::move(children)) {} + explicit VBox(Elements children) : Node(std::move(children)) {} void ComputeRequirement() override { requirement_.min_x = 0; diff --git a/src/ftxui/screen/box.cpp b/src/ftxui/screen/box.cpp index c8b84c5ff..4b96ff702 100644 --- a/src/ftxui/screen/box.cpp +++ b/src/ftxui/screen/box.cpp @@ -17,7 +17,7 @@ Box Box::Intersection(Box a, Box b) { /// @return whether (x,y) is contained inside the box. /// @ingroup screen -bool Box::Contain(int x, int y) { +bool Box::Contain(int x, int y) const { return x_min <= x && // x_max >= x && // y_min <= y && // diff --git a/src/ftxui/screen/color.cpp b/src/ftxui/screen/color.cpp index b0a59f14a..0394f40af 100644 --- a/src/ftxui/screen/color.cpp +++ b/src/ftxui/screen/color.cpp @@ -1,20 +1,36 @@ #include "ftxui/screen/color.hpp" -#include +#include // for array +#include // for literals #include "ftxui/screen/color_info.hpp" // for GetColorInfo, ColorInfo -#include "ftxui/screen/terminal.hpp" // for Terminal, Terminal::Color, Terminal::Palette256, Terminal::TrueColor +#include "ftxui/screen/terminal.hpp" // for ColorSupport, Color, Palette256, TrueColor namespace ftxui { +using namespace std::literals; + namespace { -const char* palette16code[16][2] = { - {"30", "40"}, {"31", "41"}, {"32", "42"}, {"33", "43"}, - {"34", "44"}, {"35", "45"}, {"36", "46"}, {"37", "47"}, - {"90", "100"}, {"91", "101"}, {"92", "102"}, {"93", "103"}, - {"94", "104"}, {"95", "105"}, {"96", "106"}, {"97", "107"}, +const std::array palette16code = { + "30", "40", // + "31", "41", // + "32", "42", // + "33", "43", // + "34", "44", // + "35", "45", // + "36", "46", // + "37", "47", // + "90", "100", // + "91", "101", // + "92", "102", // + "93", "103", // + "94", "104", // + "95", "105", // + "96", "106", // + "97", "107", // }; -} + +} // namespace bool Color::operator==(const Color& rhs) const { return red_ == rhs.red_ && green_ == rhs.green_ && blue_ == rhs.blue_ && @@ -28,42 +44,43 @@ bool Color::operator!=(const Color& rhs) const { std::string Color::Print(bool is_background_color) const { switch (type_) { case ColorType::Palette1: - return is_background_color ? "49" : "39"; + return is_background_color ? "49"s : "39"s; case ColorType::Palette16: - return palette16code[index_][is_background_color]; + return palette16code[2 * red_ + is_background_color]; // NOLINT; case ColorType::Palette256: - return (is_background_color ? "48;5;" : "38;5;") + std::to_string(index_); + return (is_background_color ? "48;5;"s : "38;5;"s) + std::to_string(red_); case ColorType::TrueColor: - return (is_background_color ? "48;2;" : "38;2;") // - + std::to_string(red_) + ";" // - + std::to_string(green_) + ";" // - + std::to_string(blue_); // + return (is_background_color ? "48;2;"s : "38;2;"s) // + + std::to_string(red_) + ";" // + + std::to_string(green_) + ";" // + + std::to_string(blue_); // } return ""; } /// @brief Build a transparent color. /// @ingroup screen -Color::Color() : type_(ColorType::Palette1) {} +Color::Color() = default; /// @brief Build a transparent color. /// @ingroup screen -Color::Color(Palette1) : type_(ColorType::Palette1) {} +Color::Color(Palette1 /*value*/) : Color() {} /// @brief Build a transparent using Palette16 colors. /// @ingroup screen -Color::Color(Palette16 index) : type_(ColorType::Palette16), index_(index) {} +Color::Color(Palette16 index) : type_(ColorType::Palette16), red_(index) {} /// @brief Build a transparent using Palette256 colors. /// @ingroup screen -Color::Color(Palette256 index) : type_(ColorType::Palette256), index_(index) { - if (Terminal::ColorSupport() >= Terminal::Color::Palette256) +Color::Color(Palette256 index) : type_(ColorType::Palette256), red_(index) { + if (Terminal::ColorSupport() >= Terminal::Color::Palette256) { return; + } type_ = ColorType::Palette16; - index_ = GetColorInfo(Color::Palette256(index_)).index_16; + red_ = GetColorInfo(Color::Palette256(red_)).index_16; } /// @brief Build a Color from its RGB representation. @@ -75,12 +92,17 @@ Color::Color(Palette256 index) : type_(ColorType::Palette256), index_(index) { /// @ingroup screen Color::Color(uint8_t red, uint8_t green, uint8_t blue) : type_(ColorType::TrueColor), red_(red), green_(green), blue_(blue) { - if (Terminal::ColorSupport() == Terminal::Color::TrueColor) + if (Terminal::ColorSupport() == Terminal::Color::TrueColor) { return; + } - int closest = 256 * 256 * 3; + // Find the closest coor from the database: + const int max_distance = 256 * 256 * 3; + int closest = max_distance; int best = 0; - for (int i = 16; i < 256; ++i) { + const int database_begin = 16; + const int database_end = 256; + for (int i = database_begin; i < database_end; ++i) { ColorInfo color_info = GetColorInfo(Color::Palette256(i)); int dr = color_info.red - red; int dg = color_info.green - green; @@ -94,10 +116,10 @@ Color::Color(uint8_t red, uint8_t green, uint8_t blue) if (Terminal::ColorSupport() == Terminal::Color::Palette256) { type_ = ColorType::Palette256; - index_ = best; + red_ = best; } else { type_ = ColorType::Palette16; - index_ = GetColorInfo(Color::Palette256(best)).index_16; + red_ = GetColorInfo(Color::Palette256(best)).index_16; } } @@ -122,24 +144,25 @@ Color Color::RGB(uint8_t red, uint8_t green, uint8_t blue) { /// @ingroup screen // static Color Color::HSV(uint8_t h, uint8_t s, uint8_t v) { - if (s == 0) + if (s == 0) { return Color(v, v, v); + } - uint8_t region = h / 43; - uint8_t remainder = (h - (region * 43)) * 6; - uint8_t p = (v * (255 - s)) >> 8; - uint8_t q = (v * (255 - ((s * remainder) >> 8))) >> 8; - uint8_t t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8; + uint8_t region = h / 43; // NOLINT + uint8_t remainder = (h - (region * 43)) * 6; // NOLINT + uint8_t p = (v * (255 - s)) >> 8; // NOLINT + uint8_t q = (v * (255 - ((s * remainder) >> 8))) >> 8; // NOLINT + uint8_t t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8; // NOLINT // clang-format off - switch (region) { - case 0: return Color(v,t,p); - case 1: return Color(q,v,p); - case 2: return Color(p,v,t); - case 3: return Color(p,q,v); - case 4: return Color(t,p,v); - case 5: return Color(v,p,q); - } + switch (region) { // NOLINT + case 0: return Color(v,t,p); // NOLINT + case 1: return Color(q,v,p); // NOLINT + case 2: return Color(p,v,t); // NOLINT + case 3: return Color(p,q,v); // NOLINT + case 4: return Color(t,p,v); // NOLINT + case 5: return Color(v,p,q); // NOLINT + } // NOLINT // clang-format on return Color(0, 0, 0); @@ -147,81 +170,77 @@ Color Color::HSV(uint8_t h, uint8_t s, uint8_t v) { // static Color Color::Interpolate(float t, const Color& a, const Color& b) { - float red = 0.f; - float green = 0.f; - float blue = 0.f; - switch (a.type_) { - case ColorType::Palette1: { - if (t < 0.5) - return a; - else - return b; - } - - case ColorType::Palette16: { - ColorInfo info = GetColorInfo(Color::Palette16(a.index_)); - red = info.red * (1 - t); - green = info.green * (1 - t); - blue = info.blue * (1 - t); - break; - } - - case ColorType::Palette256: { - ColorInfo info = GetColorInfo(Color::Palette256(a.index_)); - red = info.red * (1 - t); - green = info.green * (1 - t); - blue = info.blue * (1 - t); - break; - } - - case ColorType::TrueColor: { - red = a.red_ * (1 - t); - green = a.green_ * (1 - t); - blue = a.blue_ * (1 - t); - break; + if (a.type_ == ColorType::Palette1) { + if (t < 0.5F) { // NOLINT + return a; + } else { + return b; } } - switch (b.type_) { - case ColorType::Palette1: { - if (t > 0.5) - return a; - else - return b; - } - - case ColorType::Palette16: { - ColorInfo info = GetColorInfo(Color::Palette16(b.index_)); - red += info.red * t; - green += info.green * t; - blue += info.blue * t; - break; - } - - case ColorType::Palette256: { - ColorInfo info = GetColorInfo(Color::Palette256(b.index_)); - red += info.red * t; - green += info.green * t; - blue += info.blue * t; - break; + if (b.type_ == ColorType::Palette1) { + if (t > 0.5F) { // NOLINT + return a; + } else { + return b; } + } - case ColorType::TrueColor: { - red += b.red_ * t; - green += b.green_ * t; - blue += b.blue_ * t; - break; + auto get_color = [](const Color& color, // + uint8_t* red, uint8_t* green, uint8_t* blue) { + switch (color.type_) { + case ColorType::Palette1: { + return; + } + + case ColorType::Palette16: { + ColorInfo info = GetColorInfo(Color::Palette16(color.red_)); + *red = info.red; + *green = info.green; + *blue = info.blue; + return; + } + + case ColorType::Palette256: { + ColorInfo info = GetColorInfo(Color::Palette256(color.red_)); + *red = info.red; + *green = info.green; + *blue = info.blue; + return; + } + + case ColorType::TrueColor: { + *red = color.red_; + *green = color.green_; + *blue = color.blue_; + return; + } } - } - return Color::RGB(red, green, blue); + }; + + uint8_t red_a = 0; + uint8_t green_a = 0; + uint8_t blue_a = 0; + uint8_t red_b = 0; + uint8_t green_b = 0; + uint8_t blue_b = 0; + get_color(a, &red_a, &green_a, &blue_a); + get_color(b, &red_b, &green_b, &blue_b); + + return Color::RGB(static_cast(static_cast(red_a) * (1 - t) + + static_cast(red_b) * t), + static_cast(static_cast(green_a) * (1 - t) + + static_cast(green_b) * t), + static_cast(static_cast(blue_a) * (1 - t) + + static_cast(blue_b) * t)); } inline namespace literals { Color operator""_rgb(unsigned long long int combined) { - assert(combined <= 0xffffffU); - auto const red = static_cast(combined >> 16); - auto const green = static_cast(combined >> 8); + // assert(combined <= 0xffffffU); + auto const red = static_cast(combined >> 16U); + auto const green = static_cast(combined >> 8U); auto const blue = static_cast(combined); return Color(red, green, blue); } diff --git a/src/ftxui/screen/color_info.cpp b/src/ftxui/screen/color_info.cpp index a63001117..932c8bac4 100644 --- a/src/ftxui/screen/color_info.cpp +++ b/src/ftxui/screen/color_info.cpp @@ -1,10 +1,13 @@ #include "ftxui/screen/color_info.hpp" + +#include + #include "ftxui/screen/color.hpp" // for Color, Color::Palette16, Color::Palette256 namespace ftxui { // clang-format off -const ColorInfo palette256[] = { +const std::array palette256 = {{ {"Black" , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } , {"Red" , 1 , 1 , 128 , 0 , 0 , 0 , 255 , 128 } , {"Green" , 2 , 2 , 0 , 128 , 0 , 85 , 255 , 128 } , @@ -261,14 +264,14 @@ const ColorInfo palette256[] = { {"Grey85" , 253 , 7 , 218 , 218 , 218 , 0 , 0 , 218 } , {"Grey89" , 254 , 15 , 228 , 228 , 228 , 0 , 0 , 228 } , {"Grey93" , 255 , 15 , 238 , 238 , 238 , 0 , 0 , 238 } , -} ; +}}; ColorInfo GetColorInfo(Color::Palette256 index) { - return palette256[int(index)]; + return palette256[index]; // NOLINT; } ColorInfo GetColorInfo(Color::Palette16 index) { - return palette256[int(index)]; + return palette256[index]; // NOLINT; } // clang-format off diff --git a/src/ftxui/screen/screen.cpp b/src/ftxui/screen/screen.cpp index 014589e23..529eb45ce 100644 --- a/src/ftxui/screen/screen.cpp +++ b/src/ftxui/screen/screen.cpp @@ -1,6 +1,7 @@ +#include // for uint8_t #include // for operator<<, stringstream, basic_ostream, flush, cout, ostream #include // for _Rb_tree_const_iterator, map, operator!=, operator== -#include // for allocator, allocator_traits<>::value_type +#include // for allocator #include // IWYU pragma: keep #include // for pair @@ -19,26 +20,11 @@ namespace ftxui { namespace { -static const char BOLD_SET[] = "\x1B[1m"; -static const char BOLD_RESET[] = "\x1B[22m"; // Can't use 21 here. -static const char DIM_SET[] = "\x1B[2m"; -static const char DIM_RESET[] = "\x1B[22m"; - -static const char UNDERLINED_SET[] = "\x1B[4m"; -static const char UNDERLINED_RESET[] = "\x1B[24m"; - -static const char BLINK_SET[] = "\x1B[5m"; -static const char BLINK_RESET[] = "\x1B[25m"; - -static const char INVERTED_SET[] = "\x1B[7m"; -static const char INVERTED_RESET[] = "\x1B[27m"; - -static const char MOVE_LEFT[] = "\r"; -static const char MOVE_UP[] = "\x1B[1A"; -static const char CLEAR_LINE[] = "\x1B[2K"; - -Pixel dev_null_pixel; +Pixel& dev_null_pixel() { + static Pixel pixel; + return pixel; +} #if defined(_WIN32) void WindowsEmulateVT100Terminal() { @@ -66,20 +52,49 @@ void WindowsEmulateVT100Terminal() { void UpdatePixelStyle(std::stringstream& ss, Pixel& previous, const Pixel& next) { - if (next.bold != previous.bold) - ss << (next.bold ? BOLD_SET : BOLD_RESET); + if (next == previous) { + return; + } + + if (next.bold && !previous.bold) { + ss << "\x1B[1m"; // BOLD_SET + } + + if (!next.bold && previous.bold) { + ss << "\x1B[22m"; // BOLD_RESET + } + + if (next.dim && !previous.dim) { + ss << "\x1B[2m"; // DIM_SET + } + + if (!next.dim && previous.dim) { + ss << "\x1B[22m"; // DIM_RESET + } + + if (next.underlined && !previous.underlined) { + ss << "\x1B[4m"; // UNDERLINED_SET + } + + if (!next.underlined && previous.underlined) { + ss << "\x1B[24m"; // UNDERLINED_RESET + } - if (next.dim != previous.dim) - ss << (next.dim ? DIM_SET : DIM_RESET); + if (next.blink && !previous.blink) { + ss << "\x1B[5m"; // BLINK_SET + } - if (next.underlined != previous.underlined) - ss << (next.underlined ? UNDERLINED_SET : UNDERLINED_RESET); + if (!next.blink && previous.blink) { + ss << "\x1B[25m"; // BLINK_RESET + } - if (next.blink != previous.blink) - ss << (next.blink ? BLINK_SET : BLINK_RESET); + if (next.inverted && !previous.inverted) { + ss << "\x1B[7m"; // INVERTED_SET + } - if (next.inverted != previous.inverted) - ss << (next.inverted ? INVERTED_SET : INVERTED_RESET); + if (!next.inverted && previous.inverted) { + ss << "\x1B[27m"; // INVERTED_RESET + } if (next.foreground_color != previous.foreground_color || next.background_color != previous.background_color) { @@ -91,31 +106,31 @@ void UpdatePixelStyle(std::stringstream& ss, } struct TileEncoding { - unsigned int left : 2; - unsigned int top : 2; - unsigned int right : 2; - unsigned int down : 2; - unsigned int round : 1; + uint8_t left : 2; + uint8_t top : 2; + uint8_t right : 2; + uint8_t down : 2; + uint8_t round : 1; // clang-format off bool operator<(const TileEncoding& other) const { - if (left < other.left) return true; - if (left > other.left) return false; - if (top < other.top) return true; - if (top > other.top) return false; - if (right < other.right) return true; - if (right > other.right) return false; - if (down < other.down) return true; - if (down > other.down) return false; - if (round < other.round) return true; - if (round > other.round) return false; + if (left < other.left) { return true; } + if (left > other.left) { return false; } + if (top < other.top) { return true; } + if (top > other.top) { return false; } + if (right < other.right) { return true; } + if (right > other.right) { return false; } + if (down < other.down) { return true; } + if (down > other.down) { return false; } + if (round < other.round) { return true; } + if (round > other.round) { return false; } return false; } // clang-format on }; // clang-format off -const std::map tile_encoding = { +const std::map tile_encoding = { // NOLINT {"─", {1, 0, 1, 0, 0}}, {"━", {2, 0, 2, 0, 0}}, @@ -257,63 +272,72 @@ const std::map tile_encoding = { // clang-format on template -const std::map InvertMap(const std::map input) { +std::map InvertMap(const std::map input) { std::map output; - for (const auto& it : input) + for (const auto& it : input) { output[it.second] = it.first; + } return output; } -const std::map tile_encoding_inverse = +const std::map tile_encoding_inverse = // NOLINT InvertMap(tile_encoding); void UpgradeLeftRight(std::string& left, std::string& right) { const auto it_left = tile_encoding.find(left); - if (it_left == tile_encoding.end()) + if (it_left == tile_encoding.end()) { return; + } const auto it_right = tile_encoding.find(right); - if (it_right == tile_encoding.end()) + if (it_right == tile_encoding.end()) { return; + } if (it_left->second.right == 0 && it_right->second.left != 0) { TileEncoding encoding_left = it_left->second; encoding_left.right = it_right->second.left; const auto it_left_upgrade = tile_encoding_inverse.find(encoding_left); - if (it_left_upgrade != tile_encoding_inverse.end()) + if (it_left_upgrade != tile_encoding_inverse.end()) { left = it_left_upgrade->second; + } } if (it_right->second.left == 0 && it_left->second.right != 0) { TileEncoding encoding_right = it_right->second; encoding_right.left = it_left->second.right; const auto it_right_upgrade = tile_encoding_inverse.find(encoding_right); - if (it_right_upgrade != tile_encoding_inverse.end()) + if (it_right_upgrade != tile_encoding_inverse.end()) { right = it_right_upgrade->second; + } } } void UpgradeTopDown(std::string& top, std::string& down) { const auto it_top = tile_encoding.find(top); - if (it_top == tile_encoding.end()) + if (it_top == tile_encoding.end()) { return; + } const auto it_down = tile_encoding.find(down); - if (it_down == tile_encoding.end()) + if (it_down == tile_encoding.end()) { return; + } if (it_top->second.down == 0 && it_down->second.top != 0) { TileEncoding encoding_top = it_top->second; encoding_top.down = it_down->second.top; const auto it_top_down = tile_encoding_inverse.find(encoding_top); - if (it_top_down != tile_encoding_inverse.end()) + if (it_top_down != tile_encoding_inverse.end()) { top = it_top_down->second; + } } if (it_down->second.top == 0 && it_top->second.down != 0) { TileEncoding encoding_down = it_down->second; encoding_down.top = it_top->second.down; const auto it_down_top = tile_encoding_inverse.find(encoding_down); - if (it_down_top != tile_encoding_inverse.end()) + if (it_down_top != tile_encoding_inverse.end()) { down = it_down_top->second; + } } } @@ -323,6 +347,18 @@ bool ShouldAttemptAutoMerge(Pixel& pixel) { } // namespace +bool Pixel::operator==(const Pixel& other) const { + return character == other.character && // + background_color == other.background_color && // + foreground_color == other.foreground_color && // + blink == other.blink && // + bold == other.bold && // + dim == other.dim && // + inverted == other.inverted && // + underlined == other.underlined && // + automerge == other.automerge; // +} + /// A fixed dimension. /// @see Fit /// @see Full @@ -409,7 +445,7 @@ std::string& Screen::at(int x, int y) { /// @param x The pixel position along the x-axis. /// @param y The pixel position along the y-axis. Pixel& Screen::PixelAt(int x, int y) { - return stencil.Contain(x, y) ? pixels_[y][x] : dev_null_pixel; + return stencil.Contain(x, y) ? pixels_[y][x] : dev_null_pixel(); } /// @brief Return a string to be printed in order to reset the cursor position @@ -431,17 +467,19 @@ Pixel& Screen::PixelAt(int x, int y) { /// /// @return The string to print in order to reset the cursor position to the /// beginning. -std::string Screen::ResetPosition(bool clear) { +std::string Screen::ResetPosition(bool clear) const { std::stringstream ss; if (clear) { - ss << MOVE_LEFT << CLEAR_LINE; + ss << "\r"; // MOVE_LEFT; + ss << "\x1b[2K"; // CLEAR_SCREEN; for (int y = 1; y < dimy_; ++y) { - ss << MOVE_UP << CLEAR_LINE; + ss << "\x1B[1A"; // MOVE_UP; + ss << "\x1B[2K"; // CLEAR_LINE; } } else { - ss << MOVE_LEFT; + ss << "\r"; // MOVE_LEFT; for (int y = 1; y < dimy_; ++y) { - ss << MOVE_UP; + ss << "\x1B[1A"; // MOVE_UP; } } return ss.str(); @@ -462,16 +500,19 @@ void Screen::ApplyShader() { for (int x = 1; x < dimx_; ++x) { // Box drawing character uses exactly 3 byte. Pixel& cur = pixels_[y][x]; - if (!ShouldAttemptAutoMerge(cur)) + if (!ShouldAttemptAutoMerge(cur)) { continue; + } Pixel& left = pixels_[y][x-1]; Pixel& top = pixels_[y-1][x]; - if (ShouldAttemptAutoMerge(left)) + if (ShouldAttemptAutoMerge(left)) { UpgradeLeftRight(left.character, cur.character); - if (ShouldAttemptAutoMerge(top)) + } + if (ShouldAttemptAutoMerge(top)) { UpgradeTopDown(top.character, cur.character); + } } } } diff --git a/src/ftxui/screen/string.cpp b/src/ftxui/screen/string.cpp index 5d9830710..fbb5a8b37 100644 --- a/src/ftxui/screen/string.cpp +++ b/src/ftxui/screen/string.cpp @@ -7,11 +7,11 @@ #include "ftxui/screen/string.hpp" -#include // for size_t -#include // for uint32_t, uint8_t -#include // for codecvt_utf8_utf16 -#include // for wstring_convert -#include // for string, basic_string, wstring, allocator +#include // for array +#include // for codecvt_utf8_utf16 +#include // for uint32_t, uint8_t +#include // for wstring_convert +#include // for string, basic_string, wstring #include "ftxui/screen/deprecated.hpp" // for wchar_width, wstring_width @@ -24,115 +24,149 @@ struct Interval { // Sorted list of non-overlapping intervals of non-spacing characters // generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" -static const Interval g_combining_characters[] = { - {0x0300, 0x036F}, {0x0483, 0x0486}, {0x0488, 0x0489}, - {0x0591, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, - {0x05C4, 0x05C5}, {0x05C7, 0x05C7}, {0x0600, 0x0603}, - {0x0610, 0x0615}, {0x064B, 0x065E}, {0x0670, 0x0670}, - {0x06D6, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED}, - {0x070F, 0x070F}, {0x0711, 0x0711}, {0x0730, 0x074A}, - {0x07A6, 0x07B0}, {0x07EB, 0x07F3}, {0x0901, 0x0902}, - {0x093C, 0x093C}, {0x0941, 0x0948}, {0x094D, 0x094D}, - {0x0951, 0x0954}, {0x0962, 0x0963}, {0x0981, 0x0981}, - {0x09BC, 0x09BC}, {0x09C1, 0x09C4}, {0x09CD, 0x09CD}, - {0x09E2, 0x09E3}, {0x0A01, 0x0A02}, {0x0A3C, 0x0A3C}, - {0x0A41, 0x0A42}, {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, - {0x0A70, 0x0A71}, {0x0A81, 0x0A82}, {0x0ABC, 0x0ABC}, - {0x0AC1, 0x0AC5}, {0x0AC7, 0x0AC8}, {0x0ACD, 0x0ACD}, - {0x0AE2, 0x0AE3}, {0x0B01, 0x0B01}, {0x0B3C, 0x0B3C}, - {0x0B3F, 0x0B3F}, {0x0B41, 0x0B43}, {0x0B4D, 0x0B4D}, - {0x0B56, 0x0B56}, {0x0B82, 0x0B82}, {0x0BC0, 0x0BC0}, - {0x0BCD, 0x0BCD}, {0x0C3E, 0x0C40}, {0x0C46, 0x0C48}, - {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, {0x0CBC, 0x0CBC}, - {0x0CBF, 0x0CBF}, {0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCD}, - {0x0CE2, 0x0CE3}, {0x0D41, 0x0D43}, {0x0D4D, 0x0D4D}, - {0x0DCA, 0x0DCA}, {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6}, - {0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E}, - {0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC}, - {0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35}, - {0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F71, 0x0F7E}, - {0x0F80, 0x0F84}, {0x0F86, 0x0F87}, {0x0F90, 0x0F97}, - {0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102D, 0x1030}, - {0x1032, 0x1032}, {0x1036, 0x1037}, {0x1039, 0x1039}, - {0x1058, 0x1059}, {0x1160, 0x11FF}, {0x135F, 0x135F}, - {0x1712, 0x1714}, {0x1732, 0x1734}, {0x1752, 0x1753}, - {0x1772, 0x1773}, {0x17B4, 0x17B5}, {0x17B7, 0x17BD}, - {0x17C6, 0x17C6}, {0x17C9, 0x17D3}, {0x17DD, 0x17DD}, - {0x180B, 0x180D}, {0x18A9, 0x18A9}, {0x1920, 0x1922}, - {0x1927, 0x1928}, {0x1932, 0x1932}, {0x1939, 0x193B}, - {0x1A17, 0x1A18}, {0x1B00, 0x1B03}, {0x1B34, 0x1B34}, - {0x1B36, 0x1B3A}, {0x1B3C, 0x1B3C}, {0x1B42, 0x1B42}, - {0x1B6B, 0x1B73}, {0x1DC0, 0x1DCA}, {0x1DFE, 0x1DFF}, - {0x200B, 0x200F}, {0x202A, 0x202E}, {0x2060, 0x2063}, - {0x206A, 0x206F}, {0x20D0, 0x20EF}, {0x302A, 0x302F}, - {0x3099, 0x309A}, {0xA806, 0xA806}, {0xA80B, 0xA80B}, - {0xA825, 0xA826}, {0xFB1E, 0xFB1E}, {0xFE00, 0xFE0F}, - {0xFE20, 0xFE23}, {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, - {0x10A01, 0x10A03}, {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F}, - {0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, {0x1D167, 0x1D169}, - {0x1D173, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD}, - {0x1D242, 0x1D244}, {0xE0001, 0xE0001}, {0xE0020, 0xE007F}, - {0xE0100, 0xE01EF}, +const std::array g_combining_characters = { + Interval{0x0300, 0x036F}, Interval{0x0483, 0x0486}, + Interval{0x0488, 0x0489}, Interval{0x0591, 0x05BD}, + Interval{0x05BF, 0x05BF}, Interval{0x05C1, 0x05C2}, + Interval{0x05C4, 0x05C5}, Interval{0x05C7, 0x05C7}, + Interval{0x0600, 0x0603}, Interval{0x0610, 0x0615}, + Interval{0x064B, 0x065E}, Interval{0x0670, 0x0670}, + Interval{0x06D6, 0x06E4}, Interval{0x06E7, 0x06E8}, + Interval{0x06EA, 0x06ED}, Interval{0x070F, 0x070F}, + Interval{0x0711, 0x0711}, Interval{0x0730, 0x074A}, + Interval{0x07A6, 0x07B0}, Interval{0x07EB, 0x07F3}, + Interval{0x0901, 0x0902}, Interval{0x093C, 0x093C}, + Interval{0x0941, 0x0948}, Interval{0x094D, 0x094D}, + Interval{0x0951, 0x0954}, Interval{0x0962, 0x0963}, + Interval{0x0981, 0x0981}, Interval{0x09BC, 0x09BC}, + Interval{0x09C1, 0x09C4}, Interval{0x09CD, 0x09CD}, + Interval{0x09E2, 0x09E3}, Interval{0x0A01, 0x0A02}, + Interval{0x0A3C, 0x0A3C}, Interval{0x0A41, 0x0A42}, + Interval{0x0A47, 0x0A48}, Interval{0x0A4B, 0x0A4D}, + Interval{0x0A70, 0x0A71}, Interval{0x0A81, 0x0A82}, + Interval{0x0ABC, 0x0ABC}, Interval{0x0AC1, 0x0AC5}, + Interval{0x0AC7, 0x0AC8}, Interval{0x0ACD, 0x0ACD}, + Interval{0x0AE2, 0x0AE3}, Interval{0x0B01, 0x0B01}, + Interval{0x0B3C, 0x0B3C}, Interval{0x0B3F, 0x0B3F}, + Interval{0x0B41, 0x0B43}, Interval{0x0B4D, 0x0B4D}, + Interval{0x0B56, 0x0B56}, Interval{0x0B82, 0x0B82}, + Interval{0x0BC0, 0x0BC0}, Interval{0x0BCD, 0x0BCD}, + Interval{0x0C3E, 0x0C40}, Interval{0x0C46, 0x0C48}, + Interval{0x0C4A, 0x0C4D}, Interval{0x0C55, 0x0C56}, + Interval{0x0CBC, 0x0CBC}, Interval{0x0CBF, 0x0CBF}, + Interval{0x0CC6, 0x0CC6}, Interval{0x0CCC, 0x0CCD}, + Interval{0x0CE2, 0x0CE3}, Interval{0x0D41, 0x0D43}, + Interval{0x0D4D, 0x0D4D}, Interval{0x0DCA, 0x0DCA}, + Interval{0x0DD2, 0x0DD4}, Interval{0x0DD6, 0x0DD6}, + Interval{0x0E31, 0x0E31}, Interval{0x0E34, 0x0E3A}, + Interval{0x0E47, 0x0E4E}, Interval{0x0EB1, 0x0EB1}, + Interval{0x0EB4, 0x0EB9}, Interval{0x0EBB, 0x0EBC}, + Interval{0x0EC8, 0x0ECD}, Interval{0x0F18, 0x0F19}, + Interval{0x0F35, 0x0F35}, Interval{0x0F37, 0x0F37}, + Interval{0x0F39, 0x0F39}, Interval{0x0F71, 0x0F7E}, + Interval{0x0F80, 0x0F84}, Interval{0x0F86, 0x0F87}, + Interval{0x0F90, 0x0F97}, Interval{0x0F99, 0x0FBC}, + Interval{0x0FC6, 0x0FC6}, Interval{0x102D, 0x1030}, + Interval{0x1032, 0x1032}, Interval{0x1036, 0x1037}, + Interval{0x1039, 0x1039}, Interval{0x1058, 0x1059}, + Interval{0x1160, 0x11FF}, Interval{0x135F, 0x135F}, + Interval{0x1712, 0x1714}, Interval{0x1732, 0x1734}, + Interval{0x1752, 0x1753}, Interval{0x1772, 0x1773}, + Interval{0x17B4, 0x17B5}, Interval{0x17B7, 0x17BD}, + Interval{0x17C6, 0x17C6}, Interval{0x17C9, 0x17D3}, + Interval{0x17DD, 0x17DD}, Interval{0x180B, 0x180D}, + Interval{0x18A9, 0x18A9}, Interval{0x1920, 0x1922}, + Interval{0x1927, 0x1928}, Interval{0x1932, 0x1932}, + Interval{0x1939, 0x193B}, Interval{0x1A17, 0x1A18}, + Interval{0x1B00, 0x1B03}, Interval{0x1B34, 0x1B34}, + Interval{0x1B36, 0x1B3A}, Interval{0x1B3C, 0x1B3C}, + Interval{0x1B42, 0x1B42}, Interval{0x1B6B, 0x1B73}, + Interval{0x1DC0, 0x1DCA}, Interval{0x1DFE, 0x1DFF}, + Interval{0x200B, 0x200F}, Interval{0x202A, 0x202E}, + Interval{0x2060, 0x2063}, Interval{0x206A, 0x206F}, + Interval{0x20D0, 0x20EF}, Interval{0x302A, 0x302F}, + Interval{0x3099, 0x309A}, Interval{0xA806, 0xA806}, + Interval{0xA80B, 0xA80B}, Interval{0xA825, 0xA826}, + Interval{0xFB1E, 0xFB1E}, Interval{0xFE00, 0xFE0F}, + Interval{0xFE20, 0xFE23}, Interval{0xFEFF, 0xFEFF}, + Interval{0xFFF9, 0xFFFB}, Interval{0x10A01, 0x10A03}, + Interval{0x10A05, 0x10A06}, Interval{0x10A0C, 0x10A0F}, + Interval{0x10A38, 0x10A3A}, Interval{0x10A3F, 0x10A3F}, + Interval{0x1D167, 0x1D169}, Interval{0x1D173, 0x1D182}, + Interval{0x1D185, 0x1D18B}, Interval{0x1D1AA, 0x1D1AD}, + Interval{0x1D242, 0x1D244}, Interval{0xE0001, 0xE0001}, + Interval{0xE0020, 0xE007F}, Interval{0xE0100, 0xE01EF}, }; -static const Interval g_full_width_characters[] = { - {0x1100, 0x115f}, {0x2329, 0x2329}, {0x232a, 0x232a}, {0x2e80, 0x303e}, - {0x3040, 0xa4cf}, {0xac00, 0xd7a3}, {0xf900, 0xfaff}, {0xfe10, 0xfe19}, - {0xfe30, 0xfe6f}, {0xff00, 0xff60}, {0xffe0, 0xffe6}, {0x20000, 0x2fffd}, - {0x30000, 0x3fffd}, +const std::array g_full_width_characters = { + Interval{0x1100, 0x115f}, Interval{0x2329, 0x2329}, + Interval{0x232a, 0x232a}, Interval{0x2e80, 0x303e}, + Interval{0x3040, 0xa4cf}, Interval{0xac00, 0xd7a3}, + Interval{0xf900, 0xfaff}, Interval{0xfe10, 0xfe19}, + Interval{0xfe30, 0xfe6f}, Interval{0xff00, 0xff60}, + Interval{0xffe0, 0xffe6}, Interval{0x20000, 0x2fffd}, + Interval{0x30000, 0x3fffd}, }; // Find a codepoint inside a sorted list of Interval. -int Bisearch(uint32_t ucs, const Interval* table, int max) { - if (ucs < table[0].first || ucs > table[max].last) - return 0; +bool Bisearch(uint32_t ucs, const Interval* table, int max) { + if (ucs < table[0].first || ucs > table[max].last) { // NOLINT + return false; + } int min = 0; while (max >= min) { int mid = (min + max) / 2; - if (ucs > table[mid].last) + if (ucs > table[mid].last) { // NOLINT min = mid + 1; - else if (ucs < table[mid].first) + } else if (ucs < table[mid].first) { // NOLINT max = mid - 1; - else - return 1; + } else { + return true; + } } - return 0; + return false; } bool IsCombining(uint32_t ucs) { - return Bisearch(ucs, g_combining_characters, - sizeof(g_combining_characters) / sizeof(Interval) - 1); + return Bisearch(ucs, g_combining_characters.data(), + g_combining_characters.size() - 1); } bool IsFullWidth(uint32_t ucs) { - if (ucs < 0x0300) // Quick path: + if (ucs < 0x0300) // Quick path: // NOLINT return false; - return Bisearch(ucs, g_full_width_characters, - sizeof(g_full_width_characters) / sizeof(Interval) - 1); + return Bisearch(ucs, g_full_width_characters.data(), + g_full_width_characters.size() - 1); } bool IsControl(uint32_t ucs) { - if (ucs == 0) + if (ucs == 0) { return true; - if (ucs < 32) + } + if (ucs < 32) { // NOLINT return true; - if (ucs >= 0x7f && ucs < 0xa0) + } + if (ucs >= 0x7f && ucs < 0xa0) { // NOLINT return true; + } return false; } int codepoint_width(uint32_t ucs) { - if (IsControl(ucs)) + if (IsControl(ucs)) { return -1; + } - if (IsCombining(ucs)) + if (IsCombining(ucs)) { return 0; + } - if (IsFullWidth(ucs)) + if (IsFullWidth(ucs)) { return 2; + } return 1; } @@ -152,50 +186,53 @@ bool EatCodePoint(const std::string& input, uint8_t byte_1 = input[start]; // 1 byte string. - if ((byte_1 & 0b1000'0000) == 0b0000'0000) { - *ucs = byte_1 & 0b0111'1111; + if ((byte_1 & 0b1000'0000) == 0b0000'0000) { // NOLINT + *ucs = byte_1 & 0b0111'1111; // NOLINT *end = start + 1; return true; } // 2 byte string. - if ((byte_1 & 0b1110'0000) == 0b1100'0000 && start + 1 < input.size()) { + if ((byte_1 & 0b1110'0000) == 0b1100'0000 && // NOLINT + start + 1 < input.size()) { uint8_t byte_2 = input[start + 1]; *ucs = 0; - *ucs += byte_1 & 0b0001'1111; - *ucs <<= 6; - *ucs += byte_2 & 0b0011'1111; + *ucs += byte_1 & 0b0001'1111; // NOLINT + *ucs <<= 6; // NOLINT + *ucs += byte_2 & 0b0011'1111; // NOLINT *end = start + 2; return true; } // 3 byte string. - if ((byte_1 & 0b1111'0000) == 0b1110'0000 && start + 2 < input.size()) { + if ((byte_1 & 0b1111'0000) == 0b1110'0000 && // NOLINT + start + 2 < input.size()) { uint8_t byte_2 = input[start + 1]; uint8_t byte_3 = input[start + 2]; *ucs = 0; - *ucs += byte_1 & 0b0000'1111; - *ucs <<= 6; - *ucs += byte_2 & 0b0011'1111; - *ucs <<= 6; - *ucs += byte_3 & 0b0011'1111; + *ucs += byte_1 & 0b0000'1111; // NOLINT + *ucs <<= 6; // NOLINT + *ucs += byte_2 & 0b0011'1111; // NOLINT + *ucs <<= 6; // NOLINT + *ucs += byte_3 & 0b0011'1111; // NOLINT *end = start + 3; return true; } // 4 byte string. - if ((byte_1 & 0b1111'1000) == 0b1111'0000 && start + 3 < input.size()) { + if ((byte_1 & 0b1111'1000) == 0b1111'0000 && // NOLINT + start + 3 < input.size()) { uint8_t byte_2 = input[start + 1]; uint8_t byte_3 = input[start + 2]; uint8_t byte_4 = input[start + 3]; *ucs = 0; - *ucs += byte_1 & 0b0000'0111; - *ucs <<= 6; - *ucs += byte_2 & 0b0011'1111; - *ucs <<= 6; - *ucs += byte_3 & 0b0011'1111; - *ucs <<= 6; - *ucs += byte_4 & 0b0011'1111; + *ucs += byte_1 & 0b0000'0111; // NOLINT + *ucs <<= 6; // NOLINT + *ucs += byte_2 & 0b0011'1111; // NOLINT + *ucs <<= 6; // NOLINT + *ucs += byte_3 & 0b0011'1111; // NOLINT + *ucs <<= 6; // NOLINT + *ucs += byte_4 & 0b0011'1111; // NOLINT *end = start + 4; return true; } @@ -216,8 +253,9 @@ int wstring_width(const std::wstring& text) { for (const wchar_t& it : text) { int w = wchar_width(it); - if (w < 0) + if (w < 0) { return -1; + } width += w; } return width; @@ -228,14 +266,17 @@ int string_width(const std::string& input) { size_t start = 0; while (start < input.size()) { uint32_t codepoint = 0; - if (!EatCodePoint(input, start, &start, &codepoint)) + if (!EatCodePoint(input, start, &start, &codepoint)) { continue; + } - if (IsControl(codepoint)) + if (IsControl(codepoint)) { continue; + } - if (IsCombining(codepoint)) + if (IsCombining(codepoint)) { continue; + } if (IsFullWidth(codepoint)) { width += 2; @@ -254,7 +295,7 @@ std::vector Utf8ToGlyphs(const std::string& input) { size_t start = 0; size_t end = 0; while (start < input.size()) { - uint32_t codepoint; + uint32_t codepoint = 0; if (!EatCodePoint(input, start, &end, &codepoint)) { start = end; continue; @@ -264,13 +305,15 @@ std::vector Utf8ToGlyphs(const std::string& input) { start = end; // Ignore control characters. - if (IsControl(codepoint)) + if (IsControl(codepoint)) { continue; + } // Combining characters are put with the previous glyph they are modifying. if (IsCombining(codepoint)) { - if (out.size() != 0) + if (!out.empty()) { out.back() += append; + } continue; } @@ -278,7 +321,7 @@ std::vector Utf8ToGlyphs(const std::string& input) { // string to reserve the space the first is taking. if (IsFullWidth(codepoint)) { out.push_back(append); - out.push_back(""); + out.emplace_back(""); continue; } @@ -288,14 +331,13 @@ std::vector Utf8ToGlyphs(const std::string& input) { return out; } -int GlyphPosition(const std::string& input, - size_t glyph_to_skip, - size_t start) { - if (glyph_to_skip <= 0) +int GlyphPosition(const std::string& input, size_t glyph_index, size_t start) { + if (glyph_index <= 0) { return 0; + } size_t end = 0; while (start < input.size()) { - uint32_t codepoint; + uint32_t codepoint = 0; bool eaten = EatCodePoint(input, start, &end, &codepoint); // Ignore invalid, control characters and combining characters. @@ -306,14 +348,15 @@ int GlyphPosition(const std::string& input, // We eat the beginning of the next glyph. If we are eating the one // requested, return its start position immediately. - if (glyph_to_skip == 0) - return start; + if (glyph_index == 0) { + return static_cast(start); + } // Otherwise, skip this glyph and iterate: - glyph_to_skip--; + glyph_index--; start = end; } - return input.size(); + return static_cast(input.size()); } std::vector CellToGlyphIndex(const std::string& input) { @@ -323,13 +366,14 @@ std::vector CellToGlyphIndex(const std::string& input) { size_t start = 0; size_t end = 0; while (start < input.size()) { - uint32_t codepoint; + uint32_t codepoint = 0; bool eaten = EatCodePoint(input, start, &end, &codepoint); start = end; // Ignore invalid / control characters. - if (!eaten || IsControl(codepoint)) + if (!eaten || IsControl(codepoint)) { continue; + } // Combining characters are put with the previous glyph they are modifying. if (IsCombining(codepoint)) { @@ -361,19 +405,21 @@ int GlyphCount(const std::string& input) { size_t start = 0; size_t end = 0; while (start < input.size()) { - uint32_t codepoint; + uint32_t codepoint = 0; bool eaten = EatCodePoint(input, start, &end, &codepoint); start = end; // Ignore invalid characters: - if (!eaten || IsControl(codepoint)) + if (!eaten || IsControl(codepoint)) { continue; + } // Ignore combining characters, except when they don't have a preceding to // combine with. if (IsCombining(codepoint)) { - if (size == 0) + if (size == 0) { size++; + } continue; } diff --git a/src/ftxui/screen/terminal.cpp b/src/ftxui/screen/terminal.cpp index 24b03ec0a..e6341eaa7 100644 --- a/src/ftxui/screen/terminal.cpp +++ b/src/ftxui/screen/terminal.cpp @@ -18,89 +18,57 @@ namespace ftxui { +namespace { +Dimensions& FallbackSize() { #if defined(__EMSCRIPTEN__) -// This dimension was chosen arbitrarily to be able to display: -// https://arthursonzogni.com/FTXUI/examples -// This will have to be improved when someone has time to implement and need -// it. -static Dimensions fallback_size{140, 43}; -Dimensions Terminal::Size() { - return fallback_size; -} - -#elif defined(_WIN32) - -// The terminal size in VT100 was 80x24. It is still used nowadays by -// default in many terminal emulator. That's a good choice for a fallback -// value. -static Dimensions fallback_size{80, 24}; -Dimensions Terminal::Size() { - CONSOLE_SCREEN_BUFFER_INFO csbi; - - if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) { - return Dimensions{csbi.srWindow.Right - csbi.srWindow.Left + 1, - csbi.srWindow.Bottom - csbi.srWindow.Top + 1}; - } - - return fallback_size; -} - + // This dimension was chosen arbitrarily to be able to display: + // https://arthursonzogni.com/FTXUI/examples + // This will have to be improved when someone has time to implement and need + // it. + constexpr int fallback_width = 140; + constexpr int fallback_height = 43; #else -// The terminal size in VT100 was 80x24. It is still used nowadays by -// default in many terminal emulator. That's a good choice for a fallback -// value. -static Dimensions fallback_size{80, 24}; -Dimensions Terminal::Size() { - winsize w{}; - const int status = ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - // The ioctl return value result should be checked. Some operating systems - // don't support TIOCGWINSZ. - if (w.ws_col == 0 || w.ws_row == 0 || status < 0) { - return fallback_size; - } - return Dimensions{w.ws_col, w.ws_row}; -} - + // The terminal size in VT100 was 80x24. It is still used nowadays by + // default in many terminal emulator. That's a good choice for a fallback + // value. + constexpr int fallback_width = 80; + constexpr int fallback_height = 24; #endif - -/// @brief Override terminal size in case auto-detection fails -/// @param fallbackSize Terminal dimensions to fallback to -void Terminal::SetFallbackSize(const Dimensions& fallbackSize) { - fallback_size = fallbackSize; + static Dimensions g_fallback_size{fallback_width, fallback_height}; + return g_fallback_size; } -namespace { - const char* Safe(const char* c) { - return c ? c : ""; + return (c != nullptr) ? c : ""; } bool Contains(const std::string& s, const char* key) { return s.find(key) != std::string::npos; } -static bool cached = false; -Terminal::Color cached_supported_color; Terminal::Color ComputeColorSupport() { #if defined(__EMSCRIPTEN__) return Terminal::Color::TrueColor; #endif - std::string COLORTERM = Safe(std::getenv("COLORTERM")); - if (Contains(COLORTERM, "24bit") || Contains(COLORTERM, "truecolor")) + std::string COLORTERM = Safe(std::getenv("COLORTERM")); // NOLINT + if (Contains(COLORTERM, "24bit") || Contains(COLORTERM, "truecolor")) { return Terminal::Color::TrueColor; + } - std::string TERM = Safe(std::getenv("TERM")); - if (Contains(COLORTERM, "256") || Contains(TERM, "256")) + std::string TERM = Safe(std::getenv("TERM")); // NOLINT + if (Contains(COLORTERM, "256") || Contains(TERM, "256")) { return Terminal::Color::Palette256; + } #if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK) // Microsoft terminals do not properly declare themselve supporting true // colors: https://github.com/microsoft/terminal/issues/1040 // As a fallback, assume microsoft terminal are the ones not setting those // variables, and enable true colors. - if (TERM == "" && COLORTERM == "") + if (TERM == "" && COLORTERM == "") { return Terminal::Color::TrueColor; + } #endif return Terminal::Color::Palette16; @@ -108,7 +76,43 @@ Terminal::Color ComputeColorSupport() { } // namespace +Dimensions Terminal::Size() { +#if defined(__EMSCRIPTEN__) + // This dimension was chosen arbitrarily to be able to display: + // https://arthursonzogni.com/FTXUI/examples + // This will have to be improved when someone has time to implement and need + // it. + return FallbackSize(); +#elif defined(_WIN32) + CONSOLE_SCREEN_BUFFER_INFO csbi; + + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) { + return Dimensions{csbi.srWindow.Right - csbi.srWindow.Left + 1, + csbi.srWindow.Bottom - csbi.srWindow.Top + 1}; + } + + return FallbackSize(); +#else + winsize w{}; + const int status = ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); // NOLINT + // The ioctl return value result should be checked. Some operating systems + // don't support TIOCGWINSZ. + if (w.ws_col == 0 || w.ws_row == 0 || status < 0) { + return FallbackSize(); + } + return Dimensions{w.ws_col, w.ws_row}; +#endif +} + +/// @brief Override terminal size in case auto-detection fails +/// @param fallbackSize Terminal dimensions to fallback to +void Terminal::SetFallbackSize(const Dimensions& fallbackSize) { + FallbackSize() = fallbackSize; +} + Terminal::Color Terminal::ColorSupport() { + static bool cached = false; + static Terminal::Color cached_supported_color; if (!cached) { cached = true; cached_supported_color = ComputeColorSupport();