From cac94439ff56a4c01fa3635ffe184bb5891ec4d0 Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Sun, 21 Mar 2021 22:54:39 +0100 Subject: [PATCH 01/14] Add webassembly support --- CMakeLists.txt | 7 + README.md | 1 + examples/CMakeLists.txt | 11 ++ examples/dom/border.cpp | 2 +- examples/dom/color_gallery.cpp | 2 +- examples/dom/color_info_palette256.cpp | 2 +- examples/dom/color_truecolor_HSV.cpp | 2 +- examples/dom/color_truecolor_RGB.cpp | 2 +- examples/dom/dbox.cpp | 2 +- examples/dom/gauge.cpp | 3 +- examples/dom/graph.cpp | 4 +- examples/dom/hflow.cpp | 2 +- examples/dom/html_like.cpp | 4 +- examples/dom/package_manager.cpp | 3 +- examples/dom/paragraph.cpp | 2 +- examples/dom/separator.cpp | 3 +- examples/dom/size.cpp | 2 +- examples/dom/spinner.cpp | 3 +- examples/dom/style_blink.cpp | 3 +- examples/dom/style_bold.cpp | 3 +- examples/dom/style_color.cpp | 3 +- examples/dom/style_dim.cpp | 3 +- examples/dom/style_gallery.cpp | 3 +- examples/dom/style_inverted.cpp | 3 +- examples/dom/style_underlined.cpp | 3 +- examples/dom/vbox_hbox.cpp | 3 +- examples/dom/window.cpp | 2 +- examples/index.html | 164 +++++++++++++++++++++ examples/run_webassembly.sh | 6 + include/ftxui/screen/screen.hpp | 1 + src/ftxui/component/screen_interactive.cpp | 30 +++- src/ftxui/dom/text_test.cpp | 14 +- src/ftxui/dom/vbox_test.cpp | 1 + src/ftxui/screen/screen.cpp | 9 +- src/ftxui/screen/terminal.cpp | 6 +- 35 files changed, 267 insertions(+), 47 deletions(-) create mode 100644 examples/index.html create mode 100755 examples/run_webassembly.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 57efcf44..b2376131 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,6 +148,13 @@ foreach(lib screen dom component) endforeach() +if (EMSCRIPTEN) + #string(APPEND CMAKE_CXX_FLAGS " -s ASSERTIONS=1") + string(APPEND CMAKE_CXX_FLAGS " -s ASYNCIFY") + string(APPEND CMAKE_CXX_FLAGS " -s USE_PTHREADS") + string(APPEND CMAKE_CXX_FLAGS " -s PROXY_TO_PTHREAD") +endif() + if(FTXUI_ENABLE_INSTALL) include(GNUInstallDirs) install(TARGETS screen dom component diff --git a/README.md b/README.md index 194172c3..d7f32da8 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ A simple C++ library for terminal based user interface. - [Starter example project](https://github.com/ArthurSonzogni/ftxui-starter) - [Documentation](https://arthursonzogni.com/FTXUI/doc/) +- [Examples (WebAssembly)](https://arthursonzogni.com/FTXUI/examples/) - [Build using CMake](https://arthursonzogni.com/FTXUI/doc/#build-using-cmake) - [Build using nxxm](https://arthursonzogni.com/FTXUI/doc/#build-using-cmake) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ff779c0a..41e32077 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,3 +1,14 @@ add_subdirectory(component) add_subdirectory(dom) add_subdirectory(util) + +if (EMSCRIPTEN) + foreach(file + "index.html" + "run_webassembly.sh") + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/${file} + ${CMAKE_CURRENT_BINARY_DIR}/${file} + ) + endforeach(file) +endif() diff --git a/examples/dom/border.cpp b/examples/dom/border.cpp index 7a49f3e6..57fa7b3a 100644 --- a/examples/dom/border.cpp +++ b/examples/dom/border.cpp @@ -28,7 +28,7 @@ int main(int argc, const char* argv[]) { }); auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << screen.ToString() << std::endl; + screen.Print(); } // Copyright 2020 Arthur Sonzogni. All rights reserved. diff --git a/examples/dom/color_gallery.cpp b/examples/dom/color_gallery.cpp index db1c25b0..0775ad15 100644 --- a/examples/dom/color_gallery.cpp +++ b/examples/dom/color_gallery.cpp @@ -126,7 +126,7 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/color_info_palette256.cpp b/examples/dom/color_info_palette256.cpp index 56820f3f..68a1d180 100644 --- a/examples/dom/color_info_palette256.cpp +++ b/examples/dom/color_info_palette256.cpp @@ -30,7 +30,7 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/color_truecolor_HSV.cpp b/examples/dom/color_truecolor_HSV.cpp index 887f27c4..ad902bb0 100644 --- a/examples/dom/color_truecolor_HSV.cpp +++ b/examples/dom/color_truecolor_HSV.cpp @@ -26,7 +26,7 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/color_truecolor_RGB.cpp b/examples/dom/color_truecolor_RGB.cpp index ed1495ba..d35788e0 100644 --- a/examples/dom/color_truecolor_RGB.cpp +++ b/examples/dom/color_truecolor_RGB.cpp @@ -45,7 +45,7 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/dbox.cpp b/examples/dom/dbox.cpp index 67561ef1..2fc712c6 100644 --- a/examples/dom/dbox.cpp +++ b/examples/dom/dbox.cpp @@ -17,7 +17,7 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/gauge.cpp b/examples/dom/gauge.cpp index 2d7ecd34..eb2a96dd 100644 --- a/examples/dom/gauge.cpp +++ b/examples/dom/gauge.cpp @@ -19,7 +19,8 @@ int main(int argc, const char* argv[]) { }); auto screen = Screen(100, 1); Render(screen, document); - std::cout << reset_position << screen.ToString() << std::flush; + std::cout << reset_position; + screen.Print(); reset_position = screen.ResetPosition(); std::this_thread::sleep_for(0.01s); diff --git a/examples/dom/graph.cpp b/examples/dom/graph.cpp index dbf7f1ef..78c8f468 100644 --- a/examples/dom/graph.cpp +++ b/examples/dom/graph.cpp @@ -60,8 +60,8 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << reset_position << screen.ToString() << std::flush; - + std::cout << reset_position; + screen.Print(); reset_position = screen.ResetPosition(); std::this_thread::sleep_for(0.03s); diff --git a/examples/dom/hflow.cpp b/examples/dom/hflow.cpp index ef6beb22..aa140a63 100644 --- a/examples/dom/hflow.cpp +++ b/examples/dom/hflow.cpp @@ -39,7 +39,7 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << screen.ToString() << std::endl; + screen.Print(); return 0; } diff --git a/examples/dom/html_like.cpp b/examples/dom/html_like.cpp index 6485cf11..be565e8e 100644 --- a/examples/dom/html_like.cpp +++ b/examples/dom/html_like.cpp @@ -41,8 +41,8 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full()); Render(screen, document); - std::cout << reset_position << screen.ToString() << std::flush; - + std::cout << reset_position; + screen.Print(); reset_position = screen.ResetPosition(); std::this_thread::sleep_for(0.01s); diff --git a/examples/dom/package_manager.cpp b/examples/dom/package_manager.cpp index 3875945b..11cbd5f5 100644 --- a/examples/dom/package_manager.cpp +++ b/examples/dom/package_manager.cpp @@ -123,7 +123,8 @@ int main(int argc, const char* argv[]) { auto document = render(); auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << reset_position << screen.ToString() << std::flush; + std::cout << reset_position; + screen.Print(); reset_position = screen.ResetPosition(); // Simulate time. diff --git a/examples/dom/paragraph.cpp b/examples/dom/paragraph.cpp index 7ed3d149..adb1f38f 100644 --- a/examples/dom/paragraph.cpp +++ b/examples/dom/paragraph.cpp @@ -25,7 +25,7 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full(), Dimension::Full()); Render(screen, document); - std::cout << screen.ToString(); + screen.Print(); getchar(); return 0; diff --git a/examples/dom/separator.cpp b/examples/dom/separator.cpp index e5758686..f3bf1a31 100644 --- a/examples/dom/separator.cpp +++ b/examples/dom/separator.cpp @@ -18,8 +18,7 @@ int main(int argc, const char* argv[]) { border; auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - - std::cout << screen.ToString() << std::endl; + screen.Print(); return 0; } diff --git a/examples/dom/size.cpp b/examples/dom/size.cpp index 392c62e2..dfeea1d8 100644 --- a/examples/dom/size.cpp +++ b/examples/dom/size.cpp @@ -18,7 +18,7 @@ int main(int argc, const char* argv[]) { auto document = hbox(std::move(content)); auto screen = Screen::Create(Dimension::Fit(document)); Render(screen, document); - std::cout << screen.ToString() << std::endl; + screen.Print(); return 0; } diff --git a/examples/dom/spinner.cpp b/examples/dom/spinner.cpp index 52cfe871..7fff889e 100644 --- a/examples/dom/spinner.cpp +++ b/examples/dom/spinner.cpp @@ -28,7 +28,8 @@ int main(int argc, const char* argv[]) { }); auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << reset_position << screen.ToString() << std::flush; + std::cout << reset_position; + screen.Print(); reset_position = screen.ResetPosition(); std::this_thread::sleep_for(0.1s); diff --git a/examples/dom/style_blink.cpp b/examples/dom/style_blink.cpp index 0445add6..114a0d4a 100644 --- a/examples/dom/style_blink.cpp +++ b/examples/dom/style_blink.cpp @@ -12,8 +12,7 @@ int main(int argc, const char* argv[]) { }); auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/style_bold.cpp b/examples/dom/style_bold.cpp index 89cb6410..e395d784 100644 --- a/examples/dom/style_bold.cpp +++ b/examples/dom/style_bold.cpp @@ -12,8 +12,7 @@ int main(int argc, const char* argv[]) { }); auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/style_color.cpp b/examples/dom/style_color.cpp index 5c4ec509..f50fddb3 100644 --- a/examples/dom/style_color.cpp +++ b/examples/dom/style_color.cpp @@ -51,8 +51,7 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/style_dim.cpp b/examples/dom/style_dim.cpp index 53823a22..1c4d4469 100644 --- a/examples/dom/style_dim.cpp +++ b/examples/dom/style_dim.cpp @@ -12,8 +12,7 @@ int main(int argc, const char* argv[]) { }); auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/style_gallery.cpp b/examples/dom/style_gallery.cpp index a1807895..0ce864f4 100644 --- a/examples/dom/style_gallery.cpp +++ b/examples/dom/style_gallery.cpp @@ -19,8 +19,7 @@ int main(int argc, const char* argv[]) { // clang-format on auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/style_inverted.cpp b/examples/dom/style_inverted.cpp index ad930ab0..9a191810 100644 --- a/examples/dom/style_inverted.cpp +++ b/examples/dom/style_inverted.cpp @@ -11,8 +11,7 @@ int main(int argc, const char* argv[]) { }); auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/style_underlined.cpp b/examples/dom/style_underlined.cpp index 41c5fd40..dedf04ab 100644 --- a/examples/dom/style_underlined.cpp +++ b/examples/dom/style_underlined.cpp @@ -12,8 +12,7 @@ int main(int argc, const char* argv[]) { }); auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/vbox_hbox.cpp b/examples/dom/vbox_hbox.cpp index 93bb984a..92d23cdf 100644 --- a/examples/dom/vbox_hbox.cpp +++ b/examples/dom/vbox_hbox.cpp @@ -26,8 +26,7 @@ int main(int argc, const char* argv[]) { }); auto screen = Screen::Create(Dimension::Full()); Render(screen, document); - - std::cout << screen.ToString(); + screen.Print(); getchar(); return 0; diff --git a/examples/dom/window.cpp b/examples/dom/window.cpp index 18726da3..df845617 100644 --- a/examples/dom/window.cpp +++ b/examples/dom/window.cpp @@ -16,7 +16,7 @@ int main(void) { auto screen = Screen::Create(Dimension::Fixed(80), Dimension::Fixed(10)); Render(screen, document); - std::cout << screen.ToString() << '\n'; + screen.Print(); } // Copyright 2020 Arthur Sonzogni. All rights reserved. diff --git a/examples/index.html b/examples/index.html new file mode 100644 index 00000000..fde820ac --- /dev/null +++ b/examples/index.html @@ -0,0 +1,164 @@ + + + + FTXUI examples WebAssembly + + + + + +
+

FTXUI WebAssembly Example

+

+ FTXUI is a single + C++ library for terminal user interface. +

+

+ On this page, you can try all the examples contained in: ./example/ + Those are compiled using WebAssembly. +

+ +
+
+ + + + + + diff --git a/examples/run_webassembly.sh b/examples/run_webassembly.sh new file mode 100755 index 00000000..488c23c4 --- /dev/null +++ b/examples/run_webassembly.sh @@ -0,0 +1,6 @@ +#! /bin/bash +python3 -m http.server 8888 & +P1=$! +trap 'kill 0' SIGINT; P1 +python3 -m webbrowser http://localhost:8888 +wait $P1 diff --git a/include/ftxui/screen/screen.hpp b/include/ftxui/screen/screen.hpp index 7caba267..0c752027 100644 --- a/include/ftxui/screen/screen.hpp +++ b/include/ftxui/screen/screen.hpp @@ -56,6 +56,7 @@ class Screen { // Convert the screen into a printable string in the terminal. std::string ToString(); + void Print(); // Get screen dimensions. int dimx() { return dimx_; } diff --git a/src/ftxui/component/screen_interactive.cpp b/src/ftxui/component/screen_interactive.cpp index 130ce340..b4f3753b 100644 --- a/src/ftxui/component/screen_interactive.cpp +++ b/src/ftxui/component/screen_interactive.cpp @@ -38,6 +38,11 @@ namespace ftxui { namespace { +void Flush() { + // Emscripten doesn't implement flush. We interpret zero as flush. + std::cout << std::flush << (char)0; +} + constexpr int timeout_milliseconds = 20; constexpr int timeout_microseconds = timeout_milliseconds * 1000; #if defined(_WIN32) @@ -90,8 +95,25 @@ void EventListener(std::atomic* quit, } } -#else +#elif defined(__EMSCRIPTEN__) +#include +// Read char from the terminal. +void EventListener(std::atomic* quit, Sender out) { + (void)timeout_microseconds; + auto parser = TerminalInputParser(std::move(out)); + + char c; + while (!*quit) { + while(read(STDIN_FILENO, &c, 1), c) + parser.Add(c); + + emscripten_sleep(1); + parser.Timeout(1); + } +} + +#else #include int CheckStdinReady(int usec_timeout) { @@ -260,12 +282,13 @@ void ScreenInteractive::Loop(Component* component) { // Hide the cursor and show it at exit. std::cout << HIDE_CURSOR; std::cout << DISABLE_LINE_WRAP; - std::cout << std::flush; + Flush(); on_exit_functions.push([&] { std::cout << reset_cursor_position; std::cout << SHOW_CURSOR; std::cout << ENABLE_LINE_WRAP; std::cout << std::endl; + Flush(); }); auto event_listener = @@ -276,7 +299,8 @@ void ScreenInteractive::Loop(Component* component) { if (!event_receiver_->HasPending()) { std::cout << reset_cursor_position << ResetPosition(); Draw(component); - std::cout << ToString() << set_cursor_position << std::flush; + std::cout << ToString() << set_cursor_position; + Flush(); Clear(); } Event event; diff --git a/src/ftxui/dom/text_test.cpp b/src/ftxui/dom/text_test.cpp index d4f6e0e0..34fe2a55 100644 --- a/src/ftxui/dom/text_test.cpp +++ b/src/ftxui/dom/text_test.cpp @@ -42,7 +42,7 @@ TEST(TextTest, ScreenBigger2) { Screen screen(6, 2); Render(screen, element); - EXPECT_EQ("test \n ", screen.ToString()); + EXPECT_EQ("test \r\n ", screen.ToString()); } // See https://github.com/ArthurSonzogni/FTXUI/issues/2#issuecomment-504871456 @@ -51,8 +51,8 @@ TEST(TextTest, CJK) { Screen screen(6, 3); Render(screen, element); EXPECT_EQ( - "┌────┐\n" - "│测试│\n" + "┌────┐\r\n" + "│测试│\r\n" "└────┘", screen.ToString()); } @@ -63,8 +63,8 @@ TEST(TextTest, CJK_2) { Screen screen(5, 3); Render(screen, element); EXPECT_EQ( - "┌───┐\n" - "│测试\n" + "┌───┐\r\n" + "│测试\r\n" "└───┘", screen.ToString()); } @@ -75,8 +75,8 @@ TEST(TextTest, CJK_3) { Screen screen(4, 3); Render(screen, element); EXPECT_EQ( - "┌──┐\n" - "│测│\n" + "┌──┐\r\n" + "│测│\r\n" "└──┘", screen.ToString()); } diff --git a/src/ftxui/dom/vbox_test.cpp b/src/ftxui/dom/vbox_test.cpp index cffa74aa..917afd9d 100644 --- a/src/ftxui/dom/vbox_test.cpp +++ b/src/ftxui/dom/vbox_test.cpp @@ -6,6 +6,7 @@ using namespace ftxui; using namespace ftxui; std::string rotate(std::string str) { + str.erase(std::remove(str.begin(), str.end(), '\r'), str.end()); str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); return str; } diff --git a/src/ftxui/screen/screen.cpp b/src/ftxui/screen/screen.cpp index f98cc506..d83e4245 100644 --- a/src/ftxui/screen/screen.cpp +++ b/src/ftxui/screen/screen.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "ftxui/dom/node.hpp" #include "ftxui/screen/string.hpp" @@ -149,6 +150,7 @@ Screen::Screen(int dimx, int dimy) } /// Produce a std::string that can be used to print the Screen on the terminal. +/// Don't forget to flush stdout. Alternatively, you can use Screen::Print(); std::string Screen::ToString() { std::wstringstream ss; @@ -158,7 +160,7 @@ std::string Screen::ToString() { for (int y = 0; y < dimy_; ++y) { if (y != 0) { UpdatePixelStyle(ss, previous_pixel, final_pixel); - ss << '\n'; + ss << L"\r\n"; } for (int x = 0; x < dimx_;) { auto& pixel = pixels_[y][x]; @@ -181,6 +183,10 @@ std::string Screen::ToString() { return to_string(ss.str()); } +void Screen::Print() { + std::cout << ToString() << std::flush << (char)0; +} + /// @brief Access a character a given position. /// @param x The character position along the x-axis. /// @param y The character position along the y-axis. @@ -254,6 +260,7 @@ void Screen::ApplyShader() { } } } + // clang-format on } // namespace ftxui diff --git a/src/ftxui/screen/terminal.cpp b/src/ftxui/screen/terminal.cpp index fae1de8c..e86c82df 100644 --- a/src/ftxui/screen/terminal.cpp +++ b/src/ftxui/screen/terminal.cpp @@ -19,7 +19,7 @@ namespace ftxui { Terminal::Dimensions Terminal::Size() { #if defined(__EMSCRIPTEN__) - return Dimensions{80, 43}; + return Dimensions{140, 43}; #elif defined(_WIN32) CONSOLE_SCREEN_BUFFER_INFO csbi; int columns, rows; @@ -48,6 +48,10 @@ bool Contains(const std::string& s, const char* key) { 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")) return Terminal::Color::TrueColor; From 476b9deaf8894b6fe7797bcc14b4d782582c1244 Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Mon, 5 Apr 2021 22:03:37 +0200 Subject: [PATCH 02/14] Enable mouse tracking. Request terminal to send mouse position. See: https://github.com/ArthurSonzogni/FTXUI/issues/7 --- src/ftxui/component/screen_interactive.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/ftxui/component/screen_interactive.cpp b/src/ftxui/component/screen_interactive.cpp index b4f3753b..4c3eb29e 100644 --- a/src/ftxui/component/screen_interactive.cpp +++ b/src/ftxui/component/screen_interactive.cpp @@ -146,14 +146,17 @@ void EventListener(std::atomic* quit, Sender out) { #endif -static const char* HIDE_CURSOR = "\x1B[?25l"; -static const char* SHOW_CURSOR = "\x1B[?25h"; +static const char SHOW_CURSOR[] = "\x1B[?25h"; +static const char HIDE_CURSOR[] = "\x1B[?25l"; -static const char* DISABLE_LINE_WRAP = "\x1B[7l"; -static const char* ENABLE_LINE_WRAP = "\x1B[7h"; +static const char ENABLE_LINE_WRAP[] = "\x1B[7h"; +static const char DISABLE_LINE_WRAP[] = "\x1B[7l"; -static const char* USE_ALTERNATIVE_SCREEN = "\x1B[?1049h"; -static const char* USE_NORMAL_SCREEN = "\x1B[?1049l"; +static const char USE_ALTERNATIVE_SCREEN[] = "\x1B[?1049h"; +static const char USE_NORMAL_SCREEN[] = "\x1B[?1049l"; + +static const char ENABLE_MOUSE[] = "\x1B[?1000;1006;1015h"; +static const char DISABLE_MOUSE[] = "\x1B[?1000;10006;1015l"; using SignalHandler = void(int); std::stack> on_exit_functions; @@ -279,6 +282,9 @@ void ScreenInteractive::Loop(Component* component) { on_exit_functions.push([] { std::cout << USE_NORMAL_SCREEN; }); } + std::cout << ENABLE_MOUSE; + on_exit_functions.push([] { std::cout << DISABLE_MOUSE; }); + // Hide the cursor and show it at exit. std::cout << HIDE_CURSOR; std::cout << DISABLE_LINE_WRAP; From cbd13499ae32f588486afb59cb7ae2fa143deaa1 Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Sun, 18 Apr 2021 18:32:38 +0200 Subject: [PATCH 03/14] Parse mouse events. --- examples/util/print_key_press.cpp | 31 +++++- include/ftxui/component/event.hpp | 46 +++++++- src/ftxui/component/event.cpp | 64 ++++++++++- src/ftxui/component/screen_interactive.cpp | 4 +- src/ftxui/component/terminal_input_parser.cpp | 104 +++++++++++++++--- src/ftxui/component/terminal_input_parser.hpp | 46 ++++++-- 6 files changed, 251 insertions(+), 44 deletions(-) diff --git a/examples/util/print_key_press.cpp b/examples/util/print_key_press.cpp index 60c36da6..35ef936f 100644 --- a/examples/util/print_key_press.cpp +++ b/examples/util/print_key_press.cpp @@ -23,10 +23,35 @@ class DrawKey : public Component { code += L" " + std::to_wstring((unsigned int)it); code = L"(" + code + L" ) -> "; - if (keys[i].is_character()) - code += keys[i].character(); - else + if (keys[i].is_character()) { + code += std::wstring(L"character(") + keys[i].character() + L")"; + } else if (keys[i].is_mouse_move()) { + code += L"mouse_move(" + // + std::to_wstring(keys[i].mouse_x()) + L"," + + std::to_wstring(keys[i].mouse_y()) + L")"; + } else if (keys[i].is_mouse_up()) { + code += L"mouse_up(" + // + std::to_wstring(keys[i].mouse_x()) + L"," + + std::to_wstring(keys[i].mouse_y()) + L")"; + } else if (keys[i].is_mouse_left_down()) { + code += L"mouse_left_down(" + // + std::to_wstring(keys[i].mouse_x()) + L"," + + std::to_wstring(keys[i].mouse_y()) + L")"; + } else if (keys[i].is_mouse_left_move()) { + code += L"mouse_left_move(" + // + std::to_wstring(keys[i].mouse_x()) + L"," + + std::to_wstring(keys[i].mouse_y()) + L")"; + } else if (keys[i].is_mouse_right_down()) { + code += L"mouse_right_down(" + // + std::to_wstring(keys[i].mouse_x()) + L"," + + std::to_wstring(keys[i].mouse_y()) + L")"; + } else if (keys[i].is_mouse_right_move()) { + code += L"mouse_right_move(" + // + std::to_wstring(keys[i].mouse_x()) + L"," + + std::to_wstring(keys[i].mouse_y()) + L")"; + } else { code += L"(special)"; + } children.push_back(text(code)); } return window(text(L"keys"), vbox(std::move(children))); diff --git a/include/ftxui/component/event.hpp b/include/ftxui/component/event.hpp index 14e826a9..40ab123a 100644 --- a/include/ftxui/component/event.hpp +++ b/include/ftxui/component/event.hpp @@ -26,8 +26,14 @@ struct Event { static Event Character(char); static Event Character(wchar_t); - static Event Character(const std::string&); - static Event Special(const std::string&); + static Event Character(std::string); + static Event Special(std::string); + static Event MouseMove(std::string, int x, int y); + static Event MouseUp(std::string, int x, int y); + static Event MouseLeftMove(std::string, int x, int y); + static Event MouseLeftDown(std::string, int x, int y); + static Event MouseRightMove(std::string, int x, int y); + static Event MouseRightDown(std::string, int x, int y); // --- Arrow --- static const Event ArrowLeft; @@ -48,17 +54,47 @@ struct Event { static Event Custom; //--- Method section --------------------------------------------------------- - bool is_character() const { return is_character_; } + bool is_character() const { return type_ == Type::Character;} wchar_t character() const { return character_; } + + bool is_mouse_left_down() const { return type_ == Type::MouseLeftDown; } + bool is_mouse_left_move() const { return type_ == Type::MouseLeftMove; } + bool is_mouse_right_down() const { return type_ == Type::MouseRightDown; } + bool is_mouse_right_move() const { return type_ == Type::MouseRightMove; } + bool is_mouse_up() const { return type_ == Type::MouseUp; } + bool is_mouse_move() const { return type_ == Type::MouseMove; } + int mouse_x() const { return mouse_.x; } + int mouse_y() const { return mouse_.y; } + const std::string& input() const { return input_; } bool operator==(const Event& other) const { return input_ == other.input_; } //--- State section ---------------------------------------------------------- private: + enum class Type { + Unknown, + Character, + MouseMove, + MouseUp, + MouseLeftDown, + MouseLeftMove, + MouseRightDown, + MouseRightMove, + }; + + struct Mouse { + int x; + int y; + }; + + Type type_ = Type::Unknown; + + union { + wchar_t character_ = U'?'; + Mouse mouse_; + }; std::string input_; - bool is_character_ = false; - wchar_t character_ = U'?'; }; diff --git a/src/ftxui/component/event.cpp b/src/ftxui/component/event.cpp index 29fc9c16..5dc9e778 100644 --- a/src/ftxui/component/event.cpp +++ b/src/ftxui/component/event.cpp @@ -6,11 +6,11 @@ namespace ftxui { // static -Event Event::Character(const std::string& input) { +Event Event::Character(std::string input) { Event event; - event.input_ = input; - event.is_character_ = true; event.character_ = to_wstring(input)[0]; + event.input_ = std::move(input); + event.type_ = Type::Character; return event; } @@ -23,13 +23,67 @@ Event Event::Character(char c) { Event Event::Character(wchar_t c) { Event event; event.input_ = {(char)c}; - event.is_character_ = true; + event.type_ = Type::Character; event.character_ = c; return event; } // static -Event Event::Special(const std::string& input) { +Event Event::MouseMove(std::string input, int x, int y) { + Event event; + event.input_ = std::move(input); + event.type_ = Type::MouseMove; + event.mouse_ = {x, y}; + return event; +} + +// static +Event Event::MouseUp(std::string input, int x, int y) { + Event event; + event.input_ = std::move(input); + event.type_ = Type::MouseUp; + event.mouse_ = {x, y}; + return event; +} + +// static +Event Event::MouseLeftDown(std::string input, int x, int y) { + Event event; + event.input_ = std::move(input); + event.type_ = Type::MouseLeftDown; + event.mouse_ = {x, y}; + return event; +} + +// static +Event Event::MouseLeftMove(std::string input, int x, int y) { + Event event; + event.input_ = std::move(input); + event.type_ = Type::MouseLeftMove; + event.mouse_ = {x, y}; + return event; +} + +// static +Event Event::MouseRightDown(std::string input, int x, int y) { + Event event; + event.input_ = std::move(input); + event.type_ = Type::MouseRightDown; + event.mouse_ = {x, y}; + return event; +} + +// static +Event Event::MouseRightMove(std::string input, int x, int y) { + Event event; + event.input_ = std::move(input); + event.type_ = Type::MouseRightMove; + event.mouse_ = {x, y}; + return event; +} + +// static +Event Event::Special(std::string input) { Event event; event.input_ = std::move(input); return event; diff --git a/src/ftxui/component/screen_interactive.cpp b/src/ftxui/component/screen_interactive.cpp index 4c3eb29e..36c4c542 100644 --- a/src/ftxui/component/screen_interactive.cpp +++ b/src/ftxui/component/screen_interactive.cpp @@ -155,8 +155,8 @@ static const char DISABLE_LINE_WRAP[] = "\x1B[7l"; static const char USE_ALTERNATIVE_SCREEN[] = "\x1B[?1049h"; static const char USE_NORMAL_SCREEN[] = "\x1B[?1049l"; -static const char ENABLE_MOUSE[] = "\x1B[?1000;1006;1015h"; -static const char DISABLE_MOUSE[] = "\x1B[?1000;10006;1015l"; +static const char ENABLE_MOUSE[] = "\x1B[?1000;1003;1006;1015h"; +static const char DISABLE_MOUSE[] = "\x1B[?1000;1003;10006;1015l"; using SignalHandler = void(int); std::stack> on_exit_functions; diff --git a/src/ftxui/component/terminal_input_parser.cpp b/src/ftxui/component/terminal_input_parser.cpp index 78e0fdda..de73bd56 100644 --- a/src/ftxui/component/terminal_input_parser.cpp +++ b/src/ftxui/component/terminal_input_parser.cpp @@ -30,28 +30,56 @@ bool TerminalInputParser::Eat() { return position_ < (int)pending_.size(); } -void TerminalInputParser::Send(TerminalInputParser::Type type) { - switch (type) { +void TerminalInputParser::Send(TerminalInputParser::Output output) { + switch (output.type) { case UNCOMPLETED: return; case DROP: - pending_.clear(); - return; + break; case CHARACTER: out_->Send(Event::Character(std::move(pending_))); - pending_.clear(); - return; + break; case SPECIAL: out_->Send(Event::Special(std::move(pending_))); - pending_.clear(); - return; + break; + + case MOUSE_MOVE: + out_->Send( + Event::MouseMove(std::move(pending_), output.mouse.x, output.mouse.y)); + break; + + case MOUSE_UP: + out_->Send( + Event::MouseUp(std::move(pending_), output.mouse.x, output.mouse.y)); + break; + + case MOUSE_LEFT_DOWN: + out_->Send(Event::MouseLeftDown(std::move(pending_), output.mouse.x, + output.mouse.y)); + break; + + case MOUSE_LEFT_MOVE: + out_->Send(Event::MouseLeftMove(std::move(pending_), output.mouse.x, + output.mouse.y)); + break; + + case MOUSE_RIGHT_DOWN: + out_->Send(Event::MouseRightDown(std::move(pending_), output.mouse.x, + output.mouse.y)); + break; + + case MOUSE_RIGHT_MOVE: + out_->Send(Event::MouseRightMove(std::move(pending_), output.mouse.x, + output.mouse.y)); + break; } + pending_.clear(); } -TerminalInputParser::Type TerminalInputParser::Parse() { +TerminalInputParser::Output TerminalInputParser::Parse() { if (!Eat()) return UNCOMPLETED; @@ -75,7 +103,7 @@ TerminalInputParser::Type TerminalInputParser::Parse() { return ParseUTF8(); } -TerminalInputParser::Type TerminalInputParser::ParseUTF8() { +TerminalInputParser::Output TerminalInputParser::ParseUTF8() { unsigned char head = static_cast(Current()); for (int i = 0; i < 3; ++i, head <<= 1) { if ((head & 0b11000000) != 0b11000000) @@ -86,7 +114,7 @@ TerminalInputParser::Type TerminalInputParser::ParseUTF8() { return CHARACTER; } -TerminalInputParser::Type TerminalInputParser::ParseESC() { +TerminalInputParser::Output TerminalInputParser::ParseESC() { if (!Eat()) return UNCOMPLETED; switch (Current()) { @@ -103,7 +131,7 @@ TerminalInputParser::Type TerminalInputParser::ParseESC() { } } -TerminalInputParser::Type TerminalInputParser::ParseDCS() { +TerminalInputParser::Output TerminalInputParser::ParseDCS() { // Parse until the string terminator ST. while (1) { if (!Eat()) @@ -122,19 +150,35 @@ TerminalInputParser::Type TerminalInputParser::ParseDCS() { } } -TerminalInputParser::Type TerminalInputParser::ParseCSI() { +TerminalInputParser::Output TerminalInputParser::ParseCSI() { + int argument; + std::vector arguments; while (true) { if (!Eat()) return UNCOMPLETED; - if (Current() >= '0' && Current() <= '9') + if (Current() >= '0' && Current() <= '9') { + argument *= 10; + argument += int(Current() - '0'); continue; + } - if (Current() == ';') + if (Current() == ';') { + arguments.push_back(argument); + argument = 0; continue; + } - if (Current() >= ' ' && Current() <= '~') - return SPECIAL; + if (Current() >= ' ' && Current() <= '~') { + arguments.push_back(argument); + argument = 0; + switch (Current()) { + case 'M': + return ParseMouse(std::move(arguments)); + default: + return SPECIAL; + } + } // Invalid ESC in CSI. if (Current() == '\x1B') @@ -142,7 +186,7 @@ TerminalInputParser::Type TerminalInputParser::ParseCSI() { } } -TerminalInputParser::Type TerminalInputParser::ParseOSC() { +TerminalInputParser::Output TerminalInputParser::ParseOSC() { // Parse until the string terminator ST. while (true) { if (!Eat()) @@ -156,4 +200,28 @@ TerminalInputParser::Type TerminalInputParser::ParseOSC() { return SPECIAL; } } + +TerminalInputParser::Output TerminalInputParser::ParseMouse( + std::vector arguments) { + if (arguments.size() != 3) + return SPECIAL; + switch(arguments[0]) { + case 32: + return Output(MOUSE_LEFT_DOWN, arguments[1], arguments[2]); + case 64: + return Output(MOUSE_LEFT_MOVE, arguments[1], arguments[2]); + + case 34: + return Output(MOUSE_RIGHT_DOWN, arguments[1], arguments[2]); + case 66: + return Output(MOUSE_RIGHT_MOVE, arguments[1], arguments[2]); + + case 35: + return Output(MOUSE_UP, arguments[1], arguments[2]); + case 67: + return Output(MOUSE_MOVE, arguments[1], arguments[2]); + } + return SPECIAL; +} + } // namespace ftxui diff --git a/src/ftxui/component/terminal_input_parser.hpp b/src/ftxui/component/terminal_input_parser.hpp index ac0df243..72fc0952 100644 --- a/src/ftxui/component/terminal_input_parser.hpp +++ b/src/ftxui/component/terminal_input_parser.hpp @@ -20,18 +20,42 @@ class TerminalInputParser { bool Eat(); enum Type { - UNCOMPLETED = 0, - DROP = 1, - CHARACTER = 2, - SPECIAL = 3, + UNCOMPLETED, + DROP, + CHARACTER, + SPECIAL, + MOUSE_UP, + MOUSE_MOVE, + MOUSE_LEFT_DOWN, + MOUSE_LEFT_MOVE, + MOUSE_RIGHT_DOWN, + MOUSE_RIGHT_MOVE, }; - void Send(Type type); - Type Parse(); - Type ParseUTF8(); - Type ParseESC(); - Type ParseDCS(); - Type ParseCSI(); - Type ParseOSC(); + + struct Mouse { + int x; + int y; + Mouse(int x, int y) : x(x), y(y) {} + }; + + struct Output { + Type type; + union { + Mouse mouse; + }; + + Output(Type type) : type(type) {} + Output(Type type, int x, int y) : type(type), mouse(x, y) {} + }; + + void Send(Output type); + Output Parse(); + Output ParseUTF8(); + Output ParseESC(); + Output ParseDCS(); + Output ParseCSI(); + Output ParseOSC(); + Output ParseMouse(std::vector arguments); Sender out_; int position_ = -1; From d685a8655e498dce26fd8883321f81132c6f026f Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Sun, 18 Apr 2021 18:42:42 +0200 Subject: [PATCH 04/14] Parse mouse middle --- examples/util/print_key_press.cpp | 8 ++++++++ include/ftxui/component/event.hpp | 6 ++++++ src/ftxui/component/event.cpp | 20 ++++++++++++++++++- src/ftxui/component/terminal_input_parser.cpp | 15 ++++++++++++++ src/ftxui/component/terminal_input_parser.hpp | 2 ++ 5 files changed, 50 insertions(+), 1 deletion(-) diff --git a/examples/util/print_key_press.cpp b/examples/util/print_key_press.cpp index 35ef936f..3cfd57fd 100644 --- a/examples/util/print_key_press.cpp +++ b/examples/util/print_key_press.cpp @@ -41,6 +41,14 @@ class DrawKey : public Component { code += L"mouse_left_move(" + // std::to_wstring(keys[i].mouse_x()) + L"," + std::to_wstring(keys[i].mouse_y()) + L")"; + } else if (keys[i].is_mouse_middle_down()) { + code += L"mouse_middle_down(" + // + std::to_wstring(keys[i].mouse_x()) + L"," + + std::to_wstring(keys[i].mouse_y()) + L")"; + } else if (keys[i].is_mouse_middle_move()) { + code += L"mouse_middle_move(" + // + std::to_wstring(keys[i].mouse_x()) + L"," + + std::to_wstring(keys[i].mouse_y()) + L")"; } else if (keys[i].is_mouse_right_down()) { code += L"mouse_right_down(" + // std::to_wstring(keys[i].mouse_x()) + L"," + diff --git a/include/ftxui/component/event.hpp b/include/ftxui/component/event.hpp index 40ab123a..833ac7d8 100644 --- a/include/ftxui/component/event.hpp +++ b/include/ftxui/component/event.hpp @@ -32,6 +32,8 @@ struct Event { static Event MouseUp(std::string, int x, int y); static Event MouseLeftMove(std::string, int x, int y); static Event MouseLeftDown(std::string, int x, int y); + static Event MouseMiddleMove(std::string, int x, int y); + static Event MouseMiddleDown(std::string, int x, int y); static Event MouseRightMove(std::string, int x, int y); static Event MouseRightDown(std::string, int x, int y); @@ -59,6 +61,8 @@ struct Event { bool is_mouse_left_down() const { return type_ == Type::MouseLeftDown; } bool is_mouse_left_move() const { return type_ == Type::MouseLeftMove; } + bool is_mouse_middle_down() const { return type_ == Type::MouseMiddleDown; } + bool is_mouse_middle_move() const { return type_ == Type::MouseMiddleMove; } bool is_mouse_right_down() const { return type_ == Type::MouseRightDown; } bool is_mouse_right_move() const { return type_ == Type::MouseRightMove; } bool is_mouse_up() const { return type_ == Type::MouseUp; } @@ -79,6 +83,8 @@ struct Event { MouseUp, MouseLeftDown, MouseLeftMove, + MouseMiddleDown, + MouseMiddleMove, MouseRightDown, MouseRightMove, }; diff --git a/src/ftxui/component/event.cpp b/src/ftxui/component/event.cpp index 5dc9e778..d55d46b7 100644 --- a/src/ftxui/component/event.cpp +++ b/src/ftxui/component/event.cpp @@ -73,6 +73,22 @@ Event Event::MouseRightDown(std::string input, int x, int y) { return event; } +// static +Event Event::MouseMiddleMove(std::string input, int x, int y) { + Event event; + event.input_ = std::move(input); + event.type_ = Type::MouseMiddleMove; + event.mouse_ = {x, y}; + return event; +} + +// static +Event Event::Special(std::string input) { + Event event; + event.input_ = std::move(input); + return event; +} + // static Event Event::MouseRightMove(std::string input, int x, int y) { Event event; @@ -83,9 +99,11 @@ Event Event::MouseRightMove(std::string input, int x, int y) { } // static -Event Event::Special(std::string input) { +Event Event::MouseMiddleDown(std::string input, int x, int y) { Event event; event.input_ = std::move(input); + event.type_ = Type::MouseMiddleDown; + event.mouse_ = {x, y}; return event; } diff --git a/src/ftxui/component/terminal_input_parser.cpp b/src/ftxui/component/terminal_input_parser.cpp index de73bd56..f348aeb6 100644 --- a/src/ftxui/component/terminal_input_parser.cpp +++ b/src/ftxui/component/terminal_input_parser.cpp @@ -66,6 +66,16 @@ void TerminalInputParser::Send(TerminalInputParser::Output output) { output.mouse.y)); break; + case MOUSE_MIDDLE_DOWN: + out_->Send(Event::MouseMiddleDown(std::move(pending_), output.mouse.x, + output.mouse.y)); + break; + + case MOUSE_MIDDLE_MOVE: + out_->Send(Event::MouseMiddleMove(std::move(pending_), output.mouse.x, + output.mouse.y)); + break; + case MOUSE_RIGHT_DOWN: out_->Send(Event::MouseRightDown(std::move(pending_), output.mouse.x, output.mouse.y)); @@ -211,6 +221,11 @@ TerminalInputParser::Output TerminalInputParser::ParseMouse( case 64: return Output(MOUSE_LEFT_MOVE, arguments[1], arguments[2]); + case 33: + return Output(MOUSE_MIDDLE_DOWN, arguments[1], arguments[2]); + case 65: + return Output(MOUSE_MIDDLE_MOVE, arguments[1], arguments[2]); + case 34: return Output(MOUSE_RIGHT_DOWN, arguments[1], arguments[2]); case 66: diff --git a/src/ftxui/component/terminal_input_parser.hpp b/src/ftxui/component/terminal_input_parser.hpp index 72fc0952..db13d598 100644 --- a/src/ftxui/component/terminal_input_parser.hpp +++ b/src/ftxui/component/terminal_input_parser.hpp @@ -28,6 +28,8 @@ class TerminalInputParser { MOUSE_MOVE, MOUSE_LEFT_DOWN, MOUSE_LEFT_MOVE, + MOUSE_MIDDLE_DOWN, + MOUSE_MIDDLE_MOVE, MOUSE_RIGHT_DOWN, MOUSE_RIGHT_MOVE, }; From 890a41a64c9109c8867f8e7eab46e8212cf5995f Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Sun, 18 Apr 2021 22:33:41 +0200 Subject: [PATCH 05/14] Add mouse implementation of most components. --- CMakeLists.txt | 1 + include/ftxui/component/button.hpp | 2 ++ include/ftxui/component/checkbox.hpp | 4 +++ include/ftxui/component/container.hpp | 3 ++ include/ftxui/component/event.hpp | 3 ++ include/ftxui/component/menu.hpp | 5 +++ include/ftxui/component/radiobox.hpp | 2 ++ include/ftxui/component/toggle.hpp | 4 +++ include/ftxui/dom/elements.hpp | 4 +++ include/ftxui/screen/box.hpp | 1 + src/ftxui/component/button.cpp | 21 ++++++++--- src/ftxui/component/checkbox.cpp | 24 ++++++++++++- src/ftxui/component/container.cpp | 14 ++++++++ src/ftxui/component/event.cpp | 22 ++++++++++++ src/ftxui/component/menu.cpp | 24 ++++++++++++- src/ftxui/component/radiobox.cpp | 30 +++++++++++++++- src/ftxui/component/screen_interactive.cpp | 5 ++- src/ftxui/component/toggle.cpp | 30 +++++++++++++--- src/ftxui/dom/reflect.cpp | 42 ++++++++++++++++++++++ src/ftxui/screen/box.cpp | 10 ++++++ 20 files changed, 239 insertions(+), 12 deletions(-) create mode 100644 src/ftxui/dom/reflect.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b2376131..92814d76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,7 @@ add_library(dom src/ftxui/dom/node.cpp src/ftxui/dom/node_decorator.cpp src/ftxui/dom/paragraph.cpp + src/ftxui/dom/reflect.cpp src/ftxui/dom/separator.cpp src/ftxui/dom/size.cpp src/ftxui/dom/spinner.cpp diff --git a/include/ftxui/component/button.hpp b/include/ftxui/component/button.hpp index c734e756..76e4186a 100644 --- a/include/ftxui/component/button.hpp +++ b/include/ftxui/component/button.hpp @@ -25,6 +25,8 @@ class Button : public Component { // Component implementation. Element Render() override; bool OnEvent(Event) override; + private: + Box box_; }; } // namespace ftxui diff --git a/include/ftxui/component/checkbox.hpp b/include/ftxui/component/checkbox.hpp index a92b8cd3..f21121b7 100644 --- a/include/ftxui/component/checkbox.hpp +++ b/include/ftxui/component/checkbox.hpp @@ -38,7 +38,11 @@ class CheckBox : public Component { bool OnEvent(Event) override; private: + bool OnMouseEvent(Event event); + int cursor_position = 0; + Box box_; + }; } // namespace ftxui diff --git a/include/ftxui/component/container.hpp b/include/ftxui/component/container.hpp index 7054be19..03cee397 100644 --- a/include/ftxui/component/container.hpp +++ b/include/ftxui/component/container.hpp @@ -36,6 +36,9 @@ class Container : public Component { int selected_ = 0; int* selector_ = nullptr; + + private: + bool OnMouseEvent(Event event); }; } // namespace ftxui diff --git a/include/ftxui/component/event.hpp b/include/ftxui/component/event.hpp index 833ac7d8..5c05578c 100644 --- a/include/ftxui/component/event.hpp +++ b/include/ftxui/component/event.hpp @@ -59,6 +59,7 @@ struct Event { bool is_character() const { return type_ == Type::Character;} wchar_t character() const { return character_; } + bool is_mouse() const; bool is_mouse_left_down() const { return type_ == Type::MouseLeftDown; } bool is_mouse_left_move() const { return type_ == Type::MouseLeftMove; } bool is_mouse_middle_down() const { return type_ == Type::MouseMiddleDown; } @@ -74,6 +75,8 @@ struct Event { bool operator==(const Event& other) const { return input_ == other.input_; } + void MoveMouse(int dx, int dy); + //--- State section ---------------------------------------------------------- private: enum class Type { diff --git a/include/ftxui/component/menu.hpp b/include/ftxui/component/menu.hpp index ece6fe89..51fb1485 100644 --- a/include/ftxui/component/menu.hpp +++ b/include/ftxui/component/menu.hpp @@ -31,6 +31,11 @@ class Menu : public Component { // Component implementation. Element Render() override; bool OnEvent(Event) override; + + private: + bool OnMouseEvent(Event); + + std::vector boxes_; }; } // namespace ftxui diff --git a/include/ftxui/component/radiobox.hpp b/include/ftxui/component/radiobox.hpp index aaf9828a..bbfc6f72 100644 --- a/include/ftxui/component/radiobox.hpp +++ b/include/ftxui/component/radiobox.hpp @@ -39,7 +39,9 @@ class RadioBox : public Component { bool OnEvent(Event) override; private: + bool OnMouseEvent(Event event); int cursor_position = 0; + std::vector boxes_; }; } // namespace ftxui diff --git a/include/ftxui/component/toggle.hpp b/include/ftxui/component/toggle.hpp index bbe095c7..846d11b3 100644 --- a/include/ftxui/component/toggle.hpp +++ b/include/ftxui/component/toggle.hpp @@ -30,6 +30,10 @@ class Toggle : public Component { // Component implementation. Element Render() override; bool OnEvent(Event) override; + + private: + bool OnMouseEvent(Event event); + std::vector boxes_; }; } // namespace ftxui diff --git a/include/ftxui/dom/elements.hpp b/include/ftxui/dom/elements.hpp index 30191635..614b1c11 100644 --- a/include/ftxui/dom/elements.hpp +++ b/include/ftxui/dom/elements.hpp @@ -5,6 +5,7 @@ #include #include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" #include "ftxui/screen/color.hpp" #include "ftxui/screen/screen.hpp" @@ -77,6 +78,9 @@ enum Direction { WIDTH, HEIGHT }; enum Constraint { LESS_THAN, EQUAL, GREATER_THAN }; Decorator size(Direction, Constraint, int value); +// -- +Decorator reflect(Box& box); + // --- Frame --- // A frame is a scrollable area. The internal area is potentially larger than // the external one. The internal area is scrolled in order to make visible the diff --git a/include/ftxui/screen/box.hpp b/include/ftxui/screen/box.hpp index 3a643027..719e1bd5 100644 --- a/include/ftxui/screen/box.hpp +++ b/include/ftxui/screen/box.hpp @@ -10,6 +10,7 @@ struct Box { int y_max; static Box Intersection(Box a, Box b); + bool Contain(int x, int y); }; } // namespace ftxui diff --git a/src/ftxui/component/button.cpp b/src/ftxui/component/button.cpp index 581298ec..82812684 100644 --- a/src/ftxui/component/button.cpp +++ b/src/ftxui/component/button.cpp @@ -5,13 +5,26 @@ namespace ftxui { Element Button::Render() { - if (Focused()) - return text(label) | border | inverted; - else - return text(label) | border; + return text(label) | // + border | // + (Focused() ? inverted : nothing) | // + reflect(box_); } bool Button::OnEvent(Event event) { + if (event.is_mouse() && box_.Contain(event.mouse_x(), event.mouse_y())) { + if (event.is_mouse_move()) { + TakeFocus(); + return true; + } + if (event.is_mouse_left_down()) { + on_click(); + return true; + } + + return false; + } + if (event == Event::Return) { on_click(); return true; diff --git a/src/ftxui/component/checkbox.cpp b/src/ftxui/component/checkbox.cpp index 9f9cfd96..ae3dc0c3 100644 --- a/src/ftxui/component/checkbox.cpp +++ b/src/ftxui/component/checkbox.cpp @@ -9,10 +9,14 @@ Element CheckBox::Render() { auto style = is_focused ? focused_style : unfocused_style; auto focus_management = is_focused ? focus : state ? select : nothing; return hbox(text(state ? checked : unchecked), - text(label) | style | focus_management); + text(label) | style | focus_management) | + reflect(box_); } bool CheckBox::OnEvent(Event event) { + if (event.is_mouse()) + return OnMouseEvent(event); + if (event == Event::Character(' ') || event == Event::Return) { state = !state; on_change(); @@ -21,6 +25,24 @@ bool CheckBox::OnEvent(Event event) { return false; } +bool CheckBox::OnMouseEvent(Event event) { + if (!box_.Contain(event.mouse_x(), event.mouse_y())) + return false; + + if (event.is_mouse_move()) { + TakeFocus(); + return true; + } + + if (event.is_mouse_left_down()) { + state = !state; + on_change(); + return true; + } + + return false; +} + } // namespace ftxui // Copyright 2020 Arthur Sonzogni. All rights reserved. diff --git a/src/ftxui/component/container.cpp b/src/ftxui/component/container.cpp index 4b55bcd8..0fdd438f 100644 --- a/src/ftxui/component/container.cpp +++ b/src/ftxui/component/container.cpp @@ -30,6 +30,9 @@ Container Container::Tab(int* selector) { } bool Container::OnEvent(Event event) { + if (event.is_mouse()) + return OnMouseEvent(event); + if (!Focused()) return false; @@ -115,6 +118,17 @@ Element Container::TabRender() { return text(L"Empty container"); } +bool Container::OnMouseEvent(Event event) { + if (selector_) + return ActiveChild()->OnEvent(event); + + for (Component* child : children_) { + if (child->OnEvent(event)) + return true; + } + return false; +} + } // namespace ftxui // Copyright 2020 Arthur Sonzogni. All rights reserved. diff --git a/src/ftxui/component/event.cpp b/src/ftxui/component/event.cpp index d55d46b7..607ea7f7 100644 --- a/src/ftxui/component/event.cpp +++ b/src/ftxui/component/event.cpp @@ -107,6 +107,28 @@ Event Event::MouseMiddleDown(std::string input, int x, int y) { return event; } +bool Event::is_mouse() const { + switch (type_) { + case Type::Unknown: + case Type::Character: + return false; + case Type::MouseMove: + case Type::MouseUp: + case Type::MouseLeftDown: + case Type::MouseLeftMove: + case Type::MouseMiddleDown: + case Type::MouseMiddleMove: + case Type::MouseRightDown: + case Type::MouseRightMove: + return true; + }; +} + +void Event::MoveMouse(int dx, int dy) { + mouse_.x += dx; + mouse_.y += dy; +} + // --- Arrow --- const Event Event::ArrowLeft = Event::Special("\x1B[D"); const Event Event::ArrowRight = Event::Special("\x1B[C"); diff --git a/src/ftxui/component/menu.cpp b/src/ftxui/component/menu.cpp index 12b5ee34..a5114936 100644 --- a/src/ftxui/component/menu.cpp +++ b/src/ftxui/component/menu.cpp @@ -8,18 +8,23 @@ namespace ftxui { Element Menu::Render() { std::vector elements; bool is_focused = Focused(); + boxes_.resize(entries.size()); for (size_t i = 0; i < entries.size(); ++i) { auto style = (selected != int(i)) ? normal_style : is_focused ? focused_style : selected_style; auto focused = (selected != int(i)) ? nothing : is_focused ? focus : select; auto icon = (selected != int(i)) ? L" " : L"> "; - elements.push_back(text(icon + entries[i]) | style | focused); + elements.push_back(text(icon + entries[i]) | style | focused | + reflect(boxes_[i])); } return vbox(std::move(elements)); } bool Menu::OnEvent(Event event) { + if (event.is_mouse()) + return OnMouseEvent(event); + if (!Focused()) return false; @@ -48,6 +53,23 @@ bool Menu::OnEvent(Event event) { return false; } +bool Menu::OnMouseEvent(Event event) { + for (int i = 0; i < boxes_.size(); ++i) { + if (!boxes_[i].Contain(event.mouse_x(), event.mouse_y())) + continue; + + if (event.is_mouse_left_down()) { + if (selected != i) { + selected = i; + TakeFocus(); + on_change(); + } + return true; + } + } + return false; +} + } // namespace ftxui // Copyright 2020 Arthur Sonzogni. All rights reserved. diff --git a/src/ftxui/component/radiobox.cpp b/src/ftxui/component/radiobox.cpp index ff7d169f..7147c862 100644 --- a/src/ftxui/component/radiobox.cpp +++ b/src/ftxui/component/radiobox.cpp @@ -8,6 +8,7 @@ namespace ftxui { Element RadioBox::Render() { std::vector elements; bool is_focused = Focused(); + boxes_.resize(entries.size()); for (size_t i = 0; i < entries.size(); ++i) { auto style = (focused == int(i) && is_focused) ? focused_style : unfocused_style; @@ -16,12 +17,15 @@ Element RadioBox::Render() { const std::wstring& symbol = selected == int(i) ? checked : unchecked; elements.push_back(hbox(text(symbol), text(entries[i]) | style) | - focus_management); + focus_management | reflect(boxes_[i])); } return vbox(std::move(elements)); } bool RadioBox::OnEvent(Event event) { + if (event.is_mouse()) + return OnMouseEvent(event); + if (!Focused()) return false; @@ -50,6 +54,30 @@ bool RadioBox::OnEvent(Event event) { return false; } +bool RadioBox::OnMouseEvent(Event event) { + for (int i = 0; i < boxes_.size(); ++i) { + if (!boxes_[i].Contain(event.mouse_x(), event.mouse_y())) + continue; + + if (event.is_mouse_move()) { + focused = i; + TakeFocus(); + return true; + } + + if (event.is_mouse_left_down()) { + cursor_position = i; + TakeFocus(); + if (selected != i) { + selected = i; + on_change(); + } + return true; + } + } + return false; +} + } // namespace ftxui // Copyright 2020 Arthur Sonzogni. All rights reserved. diff --git a/src/ftxui/component/screen_interactive.cpp b/src/ftxui/component/screen_interactive.cpp index 36c4c542..6b3365c3 100644 --- a/src/ftxui/component/screen_interactive.cpp +++ b/src/ftxui/component/screen_interactive.cpp @@ -310,8 +310,11 @@ void ScreenInteractive::Loop(Component* component) { Clear(); } Event event; - if (event_receiver_->Receive(&event)) + if (event_receiver_->Receive(&event)) { + if (event.is_mouse()) + event.MoveMouse(-1, -1); component->OnEvent(event); + } } event_listener.join(); diff --git a/src/ftxui/component/toggle.cpp b/src/ftxui/component/toggle.cpp index c7be19e2..0437d008 100644 --- a/src/ftxui/component/toggle.cpp +++ b/src/ftxui/component/toggle.cpp @@ -7,6 +7,8 @@ namespace ftxui { Element Toggle::Render() { bool is_focused = Focused(); + boxes_.resize(entries.size()); + Elements children; for (size_t i = 0; i < entries.size(); ++i) { // Separator. @@ -14,16 +16,19 @@ Element Toggle::Render() { children.push_back(separator()); // Entry. - auto style = (selected != int(i)) - ? normal_style - : is_focused ? focused_style : selected_style; + auto style = (selected != int(i)) ? normal_style + : is_focused ? focused_style + : selected_style; auto focused = (selected != int(i)) ? nothing : is_focused ? focus : select; - children.push_back(text(entries[i]) | style | focused); + children.push_back(text(entries[i]) | style | focused | reflect(boxes_[i])); } return hbox(std::move(children)); } bool Toggle::OnEvent(Event event) { + if (event.is_mouse()) + return OnMouseEvent(event); + int old_selected = selected; if (event == Event::ArrowLeft || event == Event::Character('h')) selected--; @@ -49,6 +54,23 @@ bool Toggle::OnEvent(Event event) { return false; } +bool Toggle::OnMouseEvent(Event event) { + for (int i = 0; i < boxes_.size(); ++i) { + if (!boxes_[i].Contain(event.mouse_x(), event.mouse_y())) + continue; + + if (event.is_mouse_left_down()) { + if (selected != i) { + selected = i; + TakeFocus(); + on_change(); + } + return true; + } + } + return false; +} + } // namespace ftxui // Copyright 2020 Arthur Sonzogni. All rights reserved. diff --git a/src/ftxui/dom/reflect.cpp b/src/ftxui/dom/reflect.cpp new file mode 100644 index 00000000..10e71947 --- /dev/null +++ b/src/ftxui/dom/reflect.cpp @@ -0,0 +1,42 @@ +#include +#include "ftxui/dom/elements.hpp" +#include "ftxui/dom/node.hpp" +#include "ftxui/dom/node_decorator.hpp" + +namespace ftxui { + +Box box; + +// Helper class. +class Reflect : public Node { + public: + Reflect(Element child, Box& box) + : Node(unpack(std::move(child))), box_(box) {} + ~Reflect() override {} + + void ComputeRequirement() final { + Node::ComputeRequirement(); + requirement_ = children[0]->requirement(); + } + + void SetBox(Box box) final { + box_ = box; + Node::SetBox(box_); + children[0]->SetBox(box_); + } + + private: + Box& box_; +}; + +Decorator reflect(Box& box) { + return [&](Element child) -> Element { + return std::make_shared(std::move(child), box); + }; +} + +} // namespace ftxui + +// 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/src/ftxui/screen/box.cpp b/src/ftxui/screen/box.cpp index b8ed1ee8..07826f81 100644 --- a/src/ftxui/screen/box.cpp +++ b/src/ftxui/screen/box.cpp @@ -14,6 +14,16 @@ Box Box::Intersection(Box a, Box b) { std::min(a.y_max, b.y_max), }; } + +/// @return whether (x,y) is contained inside the box. +/// @ingroup screen +bool Box::Contain(int x, int y) { + return x_min <= x && // + x_max >= x && // + y_min <= y && // + y_max >= y; +} + } // namespace ftxui // Copyright 2020 Arthur Sonzogni. All rights reserved. From 8037a5fa5f2d81d82b8d36b989c34c3a16502f7a Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Sat, 24 Apr 2021 18:16:13 +0200 Subject: [PATCH 06/14] Improve mouse support for menu and toggle. --- examples/component/menu_style.cpp | 9 ++++-- examples/util/print_key_press.cpp | 2 +- include/ftxui/component/event.hpp | 3 ++ include/ftxui/component/menu.hpp | 4 ++- .../ftxui/component/screen_interactive.hpp | 3 ++ include/ftxui/component/toggle.hpp | 6 ++-- src/ftxui/component/button.cpp | 6 ++-- src/ftxui/component/event.cpp | 9 ++++++ src/ftxui/component/menu.cpp | 25 +++++++++++------ src/ftxui/component/screen_interactive.cpp | 25 +++++++++++++---- src/ftxui/component/terminal_input_parser.cpp | 19 ++++++++++++- src/ftxui/component/terminal_input_parser.hpp | 2 ++ .../component/terminal_input_parser_test.cpp | 19 +++++++++++++ src/ftxui/component/toggle.cpp | 28 +++++++++++-------- 14 files changed, 124 insertions(+), 36 deletions(-) diff --git a/examples/component/menu_style.cpp b/examples/component/menu_style.cpp index 839d2630..da1fb684 100644 --- a/examples/component/menu_style.cpp +++ b/examples/component/menu_style.cpp @@ -13,7 +13,7 @@ class MyComponent : public Component { MyComponent() { Add(&container); - for (Menu* menu : {&menu_1, &menu_2, &menu_3, &menu_4, &menu_5, &menu_6}) { + for (Menu* menu : {&menu_1, &menu_2, &menu_3, &menu_4, &menu_5, &menu_6,}) { container.Add(menu); menu->entries = { L"Monkey", L"Dog", L"Cat", L"Bird", L"Elephant", @@ -21,22 +21,27 @@ class MyComponent : public Component { menu->on_enter = [this]() { on_enter(); }; } - menu_2.selected_style = color(Color::Blue); menu_2.focused_style = bold | color(Color::Blue); + menu_2.selected_style = color(Color::Blue); + menu_2.selected_focused_style = bold | color(Color::Blue); menu_3.selected_style = color(Color::Blue); menu_3.focused_style = bgcolor(Color::Blue); + menu_3.selected_focused_style = bgcolor(Color::Blue); menu_4.selected_style = bgcolor(Color::Blue); menu_4.focused_style = bgcolor(Color::BlueLight); + menu_4.selected_focused_style = bgcolor(Color::BlueLight); menu_5.normal_style = bgcolor(Color::Blue); menu_5.selected_style = bgcolor(Color::Yellow); menu_5.focused_style = bgcolor(Color::Red); + menu_5.selected_focused_style = bgcolor(Color::Red); menu_6.normal_style = dim | color(Color::Blue); menu_6.selected_style = color(Color::Blue); menu_6.focused_style = bold | color(Color::Blue); + menu_6.selected_focused_style = bold | color(Color::Blue); } std::function on_enter = []() {}; diff --git a/examples/util/print_key_press.cpp b/examples/util/print_key_press.cpp index 3cfd57fd..fbd6ff8a 100644 --- a/examples/util/print_key_press.cpp +++ b/examples/util/print_key_press.cpp @@ -17,7 +17,7 @@ class DrawKey : public Component { Element Render() override { Elements children; - for (size_t i = std::max(0, (int)keys.size() - 10); i < keys.size(); ++i) { + for (size_t i = std::max(0, (int)keys.size() - 20); i < keys.size(); ++i) { std::wstring code; for (auto& it : keys[i].input()) code += L" " + std::to_wstring((unsigned int)it); diff --git a/include/ftxui/component/event.hpp b/include/ftxui/component/event.hpp index 5c05578c..742c75cf 100644 --- a/include/ftxui/component/event.hpp +++ b/include/ftxui/component/event.hpp @@ -36,6 +36,7 @@ struct Event { static Event MouseMiddleDown(std::string, int x, int y); static Event MouseRightMove(std::string, int x, int y); static Event MouseRightDown(std::string, int x, int y); + static Event CursorReporting(std::string, int x, int y); // --- Arrow --- static const Event ArrowLeft; @@ -68,6 +69,7 @@ struct Event { bool is_mouse_right_move() const { return type_ == Type::MouseRightMove; } bool is_mouse_up() const { return type_ == Type::MouseUp; } bool is_mouse_move() const { return type_ == Type::MouseMove; } + bool is_cursor_reporting() const { return type_ == Type::CursorReporting; } int mouse_x() const { return mouse_.x; } int mouse_y() const { return mouse_.y; } @@ -90,6 +92,7 @@ struct Event { MouseMiddleMove, MouseRightDown, MouseRightMove, + CursorReporting, }; struct Mouse { diff --git a/include/ftxui/component/menu.hpp b/include/ftxui/component/menu.hpp index 51fb1485..d6213634 100644 --- a/include/ftxui/component/menu.hpp +++ b/include/ftxui/component/menu.hpp @@ -19,10 +19,12 @@ class Menu : public Component { // State. std::vector entries = {}; int selected = 0; + int focused = 0; + Decorator normal_style = nothing; Decorator focused_style = inverted; Decorator selected_style = bold; - Decorator normal_style = nothing; + Decorator selected_focused_style = focused_style | selected_style; // State update callback. std::function on_change = []() {}; diff --git a/include/ftxui/component/screen_interactive.hpp b/include/ftxui/component/screen_interactive.hpp index 33279697..8f5903a4 100644 --- a/include/ftxui/component/screen_interactive.hpp +++ b/include/ftxui/component/screen_interactive.hpp @@ -52,6 +52,9 @@ class ScreenInteractive : public Screen { std::string reset_cursor_position; std::atomic quit_ = false; + + int cursor_x_ = 0; + int cursor_y_ = 0; }; } // namespace ftxui diff --git a/include/ftxui/component/toggle.hpp b/include/ftxui/component/toggle.hpp index 846d11b3..8e9a3f65 100644 --- a/include/ftxui/component/toggle.hpp +++ b/include/ftxui/component/toggle.hpp @@ -16,12 +16,14 @@ class Toggle : public Component { ~Toggle() override = default; // State. - int selected = 0; std::vector entries = {L"On", L"Off"}; + int selected = 0; + int focused = 0; + Decorator normal_style = dim; Decorator focused_style = inverted; Decorator selected_style = bold; - Decorator normal_style = dim; + Decorator selected_focused_style = focused_style | selected_style; // Callback. std::function on_change = []() {}; diff --git a/src/ftxui/component/button.cpp b/src/ftxui/component/button.cpp index 82812684..85065c9a 100644 --- a/src/ftxui/component/button.cpp +++ b/src/ftxui/component/button.cpp @@ -5,10 +5,8 @@ namespace ftxui { Element Button::Render() { - return text(label) | // - border | // - (Focused() ? inverted : nothing) | // - reflect(box_); + auto style = Focused() ? inverted : nothing; + return text(label) | border | style | reflect(box_); } bool Button::OnEvent(Event event) { diff --git a/src/ftxui/component/event.cpp b/src/ftxui/component/event.cpp index 607ea7f7..dac8951f 100644 --- a/src/ftxui/component/event.cpp +++ b/src/ftxui/component/event.cpp @@ -107,10 +107,19 @@ Event Event::MouseMiddleDown(std::string input, int x, int y) { return event; } +Event Event::CursorReporting(std::string input, int x, int y) { + Event event; + event.input_ = std::move(input); + event.type_ = Type::CursorReporting; + event.mouse_ = {x, y}; + return event; +} + bool Event::is_mouse() const { switch (type_) { case Type::Unknown: case Type::Character: + case Type::CursorReporting: return false; case Type::MouseMove: case Type::MouseUp: diff --git a/src/ftxui/component/menu.cpp b/src/ftxui/component/menu.cpp index a5114936..c626f717 100644 --- a/src/ftxui/component/menu.cpp +++ b/src/ftxui/component/menu.cpp @@ -6,16 +6,21 @@ namespace ftxui { Element Menu::Render() { - std::vector elements; - bool is_focused = Focused(); + Elements elements; + bool is_menu_focused = Focused(); boxes_.resize(entries.size()); for (size_t i = 0; i < entries.size(); ++i) { - auto style = (selected != int(i)) - ? normal_style - : is_focused ? focused_style : selected_style; - auto focused = (selected != int(i)) ? nothing : is_focused ? focus : select; - auto icon = (selected != int(i)) ? L" " : L"> "; - elements.push_back(text(icon + entries[i]) | style | focused | + bool is_focused = (focused == int(i)) && is_menu_focused; + bool is_selected = (selected == int(i)); + + auto style = is_selected + ? (is_focused ? selected_focused_style : selected_style) + : (is_focused ? focused_style : normal_style); + auto focus_management = !is_selected ? nothing + : is_menu_focused ? focus + : select; + auto icon = is_selected ? L"> " : L" "; + elements.push_back(text(icon + entries[i]) | style | focus_management | reflect(boxes_[i])); } return vbox(std::move(elements)); @@ -41,6 +46,7 @@ bool Menu::OnEvent(Event event) { selected = std::max(0, std::min(int(entries.size()) - 1, selected)); if (selected != old_selected) { + focused = selected; on_change(); return true; } @@ -58,10 +64,11 @@ bool Menu::OnMouseEvent(Event event) { if (!boxes_[i].Contain(event.mouse_x(), event.mouse_y())) continue; + focused = i; if (event.is_mouse_left_down()) { + TakeFocus(); if (selected != i) { selected = i; - TakeFocus(); on_change(); } return true; diff --git a/src/ftxui/component/screen_interactive.cpp b/src/ftxui/component/screen_interactive.cpp index 6b3365c3..c1494215 100644 --- a/src/ftxui/component/screen_interactive.cpp +++ b/src/ftxui/component/screen_interactive.cpp @@ -156,7 +156,9 @@ static const char USE_ALTERNATIVE_SCREEN[] = "\x1B[?1049h"; static const char USE_NORMAL_SCREEN[] = "\x1B[?1049l"; static const char ENABLE_MOUSE[] = "\x1B[?1000;1003;1006;1015h"; -static const char DISABLE_MOUSE[] = "\x1B[?1000;1003;10006;1015l"; +static const char DISABLE_MOUSE[] = "\x1B[?1000;1003;1006;1015l"; + +static const char REQUEST_CURSOR_LINE[] = "\x1b[6n"; using SignalHandler = void(int); std::stack> on_exit_functions; @@ -304,17 +306,30 @@ void ScreenInteractive::Loop(Component* component) { while (!quit_) { if (!event_receiver_->HasPending()) { std::cout << reset_cursor_position << ResetPosition(); + static int i = -2; + if (i % 30 == 0) + std::cout << REQUEST_CURSOR_LINE; + ++i; Draw(component); std::cout << ToString() << set_cursor_position; Flush(); Clear(); } + Event event; - if (event_receiver_->Receive(&event)) { - if (event.is_mouse()) - event.MoveMouse(-1, -1); - component->OnEvent(event); + if (!event_receiver_->Receive(&event)) + break; + + if (event.is_cursor_reporting()) { + cursor_x_ = event.mouse_y(); + cursor_y_ = event.mouse_x(); + continue; } + + if (event.is_mouse()) + event.MoveMouse(-cursor_x_, -cursor_y_); + + component->OnEvent(event); } event_listener.join(); diff --git a/src/ftxui/component/terminal_input_parser.cpp b/src/ftxui/component/terminal_input_parser.cpp index f348aeb6..c5661544 100644 --- a/src/ftxui/component/terminal_input_parser.cpp +++ b/src/ftxui/component/terminal_input_parser.cpp @@ -85,6 +85,11 @@ void TerminalInputParser::Send(TerminalInputParser::Output output) { out_->Send(Event::MouseRightMove(std::move(pending_), output.mouse.x, output.mouse.y)); break; + + case CURSOR_REPORTING: + out_->Send(Event::CursorReporting(std::move(pending_), output.mouse.x, + output.mouse.y)); + break; } pending_.clear(); } @@ -179,12 +184,14 @@ TerminalInputParser::Output TerminalInputParser::ParseCSI() { continue; } - if (Current() >= ' ' && Current() <= '~') { + if (Current() >= ' ' && Current() <= '~' && Current() != '<') { arguments.push_back(argument); argument = 0; switch (Current()) { case 'M': return ParseMouse(std::move(arguments)); + case 'R': + return ParseCursorReporting(std::move(arguments)); default: return SPECIAL; } @@ -235,8 +242,18 @@ TerminalInputParser::Output TerminalInputParser::ParseMouse( return Output(MOUSE_UP, arguments[1], arguments[2]); case 67: return Output(MOUSE_MOVE, arguments[1], arguments[2]); + + default: + return Output(MOUSE_MOVE, arguments[1], arguments[2]); } return SPECIAL; } +TerminalInputParser::Output TerminalInputParser::ParseCursorReporting( + std::vector arguments) { + if (arguments.size() != 2) + return SPECIAL; + return Output(CURSOR_REPORTING, arguments[0], arguments[1]); +} + } // namespace ftxui diff --git a/src/ftxui/component/terminal_input_parser.hpp b/src/ftxui/component/terminal_input_parser.hpp index db13d598..bb63ad88 100644 --- a/src/ftxui/component/terminal_input_parser.hpp +++ b/src/ftxui/component/terminal_input_parser.hpp @@ -32,6 +32,7 @@ class TerminalInputParser { MOUSE_MIDDLE_MOVE, MOUSE_RIGHT_DOWN, MOUSE_RIGHT_MOVE, + CURSOR_REPORTING, }; struct Mouse { @@ -58,6 +59,7 @@ class TerminalInputParser { Output ParseCSI(); Output ParseOSC(); Output ParseMouse(std::vector arguments); + Output ParseCursorReporting(std::vector arguments); Sender out_; int position_ = -1; diff --git a/src/ftxui/component/terminal_input_parser_test.cpp b/src/ftxui/component/terminal_input_parser_test.cpp index 09bcfa40..80fbd298 100644 --- a/src/ftxui/component/terminal_input_parser_test.cpp +++ b/src/ftxui/component/terminal_input_parser_test.cpp @@ -66,6 +66,25 @@ TEST(Event, EscapeKeyEnoughWait) { EXPECT_FALSE(event_receiver->Receive(&received)); } +TEST(Event, GnomeTerminalMouse) { + auto event_receiver = MakeReceiver(); + { + auto parser = TerminalInputParser(event_receiver->MakeSender()); + parser.Add('\x1B'); + parser.Add('['); + parser.Add('<'); + parser.Add('1'); + parser.Add(';'); + parser.Add('1'); + parser.Add('M'); + } + + Event received; + EXPECT_TRUE(event_receiver->Receive(&received)); + EXPECT_TRUE(received.is_mouse()); + EXPECT_FALSE(event_receiver->Receive(&received)); +} + // 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/src/ftxui/component/toggle.cpp b/src/ftxui/component/toggle.cpp index 0437d008..525cdedd 100644 --- a/src/ftxui/component/toggle.cpp +++ b/src/ftxui/component/toggle.cpp @@ -5,22 +5,25 @@ namespace ftxui { Element Toggle::Render() { - bool is_focused = Focused(); - - boxes_.resize(entries.size()); - Elements children; + bool is_toggle_focused = Focused(); + boxes_.resize(entries.size()); for (size_t i = 0; i < entries.size(); ++i) { // Separator. if (i != 0) children.push_back(separator()); - // Entry. - auto style = (selected != int(i)) ? normal_style - : is_focused ? focused_style - : selected_style; - auto focused = (selected != int(i)) ? nothing : is_focused ? focus : select; - children.push_back(text(entries[i]) | style | focused | reflect(boxes_[i])); + bool is_focused = (focused == int(i)) && is_toggle_focused; + bool is_selected = (selected == int(i)); + + auto style = is_selected + ? (is_focused ? selected_focused_style : selected_style) + : (is_focused ? focused_style : normal_style); + auto focus_management = !is_selected ? nothing + : is_toggle_focused ? focus + : select; + children.push_back(text(entries[i]) | style | focus_management | + reflect(boxes_[i])); } return hbox(std::move(children)); } @@ -42,6 +45,7 @@ bool Toggle::OnEvent(Event event) { selected = std::max(0, std::min(int(entries.size()) - 1, selected)); if (old_selected != selected) { + focused = selected; on_change(); return true; } @@ -59,10 +63,12 @@ bool Toggle::OnMouseEvent(Event event) { if (!boxes_[i].Contain(event.mouse_x(), event.mouse_y())) continue; + TakeFocus(); + focused = i; if (event.is_mouse_left_down()) { + TakeFocus(); if (selected != i) { selected = i; - TakeFocus(); on_change(); } return true; From 0b9b6c692aa7527d95bae1c4c832c7c82b1f98a6 Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Sun, 25 Apr 2021 15:22:38 +0200 Subject: [PATCH 07/14] Improve mouse support --- CMakeLists.txt | 1 + examples/util/print_key_press.cpp | 98 ++++++++------- include/ftxui/component/event.hpp | 47 +++----- include/ftxui/component/mouse.hpp | 41 +++++++ src/ftxui/component/button.cpp | 11 +- src/ftxui/component/checkbox.cpp | 10 +- src/ftxui/component/event.cpp | 94 +-------------- src/ftxui/component/menu.cpp | 7 +- src/ftxui/component/radiobox.cpp | 12 +- src/ftxui/component/screen_interactive.cpp | 114 +++++++++++++----- src/ftxui/component/terminal_input_parser.cpp | 109 ++++++----------- src/ftxui/component/terminal_input_parser.hpp | 16 +-- .../component/terminal_input_parser_test.cpp | 65 +++++++++- src/ftxui/component/toggle.cpp | 5 +- 14 files changed, 326 insertions(+), 304 deletions(-) create mode 100644 include/ftxui/component/mouse.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 92814d76..a65cfd39 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,7 @@ add_library(component include/ftxui/component/event.hpp include/ftxui/component/input.hpp include/ftxui/component/menu.hpp + include/ftxui/component/mouse.hpp include/ftxui/component/radiobox.hpp include/ftxui/component/receiver.hpp include/ftxui/component/screen_interactive.hpp diff --git a/examples/util/print_key_press.cpp b/examples/util/print_key_press.cpp index fbd6ff8a..3ba98485 100644 --- a/examples/util/print_key_press.cpp +++ b/examples/util/print_key_press.cpp @@ -11,6 +11,60 @@ using namespace ftxui; +std::wstring Stringify(Event event) { + std::wstring out; + for (auto& it : event.input()) + out += L" " + std::to_wstring((unsigned int)it); + + out = L"(" + out + L" ) -> "; + if (event.is_character()) { + out += std::wstring(L"character(") + event.character() + L")"; + } else if (event.is_mouse()) { + out += L"mouse"; + switch (event.mouse().button) { + case Mouse::Left: + out += L"_left"; + break; + case Mouse::Middle: + out += L"_middle"; + break; + case Mouse::Right: + out += L"_right"; + break; + case Mouse::None: + out += L"_none"; + break; + case Mouse::WheelUp: + out += L"_wheel_up"; + break; + case Mouse::WheelDown: + out += L"_wheel_down"; + break; + } + switch (event.mouse().motion) { + case Mouse::Pressed: + out += L"_pressed"; + break; + case Mouse::Released: + out += L"_released"; + break; + } + if (event.mouse().control) + out += L"_control"; + if (event.mouse().shift) + out += L"_shift"; + if (event.mouse().meta) + out += L"_meta"; + + out += L"(" + // + std::to_wstring(event.mouse().x) + L"," + + std::to_wstring(event.mouse().y) + L")"; + } else { + out += L"(special)"; + } + return out; +} + class DrawKey : public Component { public: ~DrawKey() override = default; @@ -18,49 +72,7 @@ class DrawKey : public Component { Element Render() override { Elements children; for (size_t i = std::max(0, (int)keys.size() - 20); i < keys.size(); ++i) { - std::wstring code; - for (auto& it : keys[i].input()) - code += L" " + std::to_wstring((unsigned int)it); - - code = L"(" + code + L" ) -> "; - if (keys[i].is_character()) { - code += std::wstring(L"character(") + keys[i].character() + L")"; - } else if (keys[i].is_mouse_move()) { - code += L"mouse_move(" + // - std::to_wstring(keys[i].mouse_x()) + L"," + - std::to_wstring(keys[i].mouse_y()) + L")"; - } else if (keys[i].is_mouse_up()) { - code += L"mouse_up(" + // - std::to_wstring(keys[i].mouse_x()) + L"," + - std::to_wstring(keys[i].mouse_y()) + L")"; - } else if (keys[i].is_mouse_left_down()) { - code += L"mouse_left_down(" + // - std::to_wstring(keys[i].mouse_x()) + L"," + - std::to_wstring(keys[i].mouse_y()) + L")"; - } else if (keys[i].is_mouse_left_move()) { - code += L"mouse_left_move(" + // - std::to_wstring(keys[i].mouse_x()) + L"," + - std::to_wstring(keys[i].mouse_y()) + L")"; - } else if (keys[i].is_mouse_middle_down()) { - code += L"mouse_middle_down(" + // - std::to_wstring(keys[i].mouse_x()) + L"," + - std::to_wstring(keys[i].mouse_y()) + L")"; - } else if (keys[i].is_mouse_middle_move()) { - code += L"mouse_middle_move(" + // - std::to_wstring(keys[i].mouse_x()) + L"," + - std::to_wstring(keys[i].mouse_y()) + L")"; - } else if (keys[i].is_mouse_right_down()) { - code += L"mouse_right_down(" + // - std::to_wstring(keys[i].mouse_x()) + L"," + - std::to_wstring(keys[i].mouse_y()) + L")"; - } else if (keys[i].is_mouse_right_move()) { - code += L"mouse_right_move(" + // - std::to_wstring(keys[i].mouse_x()) + L"," + - std::to_wstring(keys[i].mouse_y()) + L")"; - } else { - code += L"(special)"; - } - children.push_back(text(code)); + children.push_back(text(Stringify(keys[i]))); } return window(text(L"keys"), vbox(std::move(children))); } diff --git a/include/ftxui/component/event.hpp b/include/ftxui/component/event.hpp index 742c75cf..bb87c6a1 100644 --- a/include/ftxui/component/event.hpp +++ b/include/ftxui/component/event.hpp @@ -2,6 +2,7 @@ #define FTXUI_COMPONENT_EVENT_HPP #include +#include #include #include #include @@ -28,14 +29,7 @@ struct Event { static Event Character(std::string); static Event Special(std::string); - static Event MouseMove(std::string, int x, int y); - static Event MouseUp(std::string, int x, int y); - static Event MouseLeftMove(std::string, int x, int y); - static Event MouseLeftDown(std::string, int x, int y); - static Event MouseMiddleMove(std::string, int x, int y); - static Event MouseMiddleDown(std::string, int x, int y); - static Event MouseRightMove(std::string, int x, int y); - static Event MouseRightDown(std::string, int x, int y); + static Event Mouse(std::string, Mouse mouse); static Event CursorReporting(std::string, int x, int y); // --- Arrow --- @@ -60,51 +54,38 @@ struct Event { bool is_character() const { return type_ == Type::Character;} wchar_t character() const { return character_; } - bool is_mouse() const; - bool is_mouse_left_down() const { return type_ == Type::MouseLeftDown; } - bool is_mouse_left_move() const { return type_ == Type::MouseLeftMove; } - bool is_mouse_middle_down() const { return type_ == Type::MouseMiddleDown; } - bool is_mouse_middle_move() const { return type_ == Type::MouseMiddleMove; } - bool is_mouse_right_down() const { return type_ == Type::MouseRightDown; } - bool is_mouse_right_move() const { return type_ == Type::MouseRightMove; } - bool is_mouse_up() const { return type_ == Type::MouseUp; } - bool is_mouse_move() const { return type_ == Type::MouseMove; } + bool is_mouse() const { return type_ == Type::Mouse; } + struct Mouse& mouse() { + return mouse_; + } + bool is_cursor_reporting() const { return type_ == Type::CursorReporting; } - int mouse_x() const { return mouse_.x; } - int mouse_y() const { return mouse_.y; } + int cursor_x() const { return cursor_.x; } + int cursor_y() const { return cursor_.y; } const std::string& input() const { return input_; } bool operator==(const Event& other) const { return input_ == other.input_; } - void MoveMouse(int dx, int dy); - //--- State section ---------------------------------------------------------- private: enum class Type { Unknown, Character, - MouseMove, - MouseUp, - MouseLeftDown, - MouseLeftMove, - MouseMiddleDown, - MouseMiddleMove, - MouseRightDown, - MouseRightMove, + Mouse, CursorReporting, }; + Type type_ = Type::Unknown; - struct Mouse { + struct Cursor { int x; int y; }; - Type type_ = Type::Unknown; - union { wchar_t character_ = U'?'; - Mouse mouse_; + struct Mouse mouse_; + struct Cursor cursor_; }; std::string input_; }; diff --git a/include/ftxui/component/mouse.hpp b/include/ftxui/component/mouse.hpp new file mode 100644 index 00000000..54e80d4b --- /dev/null +++ b/include/ftxui/component/mouse.hpp @@ -0,0 +1,41 @@ +namespace ftxui { + +/// @brief A mouse event. It contains the coordinate of the mouse, the button +/// pressed and the modifier (shift, ctrl, meta). +/// @ingroup component +struct Mouse { + enum Button { + Left = 0, + Middle = 1, + Right = 2, + None = 3, + WheelUp = 4, + WheelDown = 5, + }; + + enum Motion { + Released = 0, + Pressed = 1, + }; + + // Button + Button button; + + // Motion + Motion motion; + + // Modifiers: + bool shift; + bool meta; + bool control; + + // Coordinates: + int x; + int y; +}; + +} // namespace ftxui + +// 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/src/ftxui/component/button.cpp b/src/ftxui/component/button.cpp index 85065c9a..4da42ddb 100644 --- a/src/ftxui/component/button.cpp +++ b/src/ftxui/component/button.cpp @@ -10,12 +10,11 @@ Element Button::Render() { } bool Button::OnEvent(Event event) { - if (event.is_mouse() && box_.Contain(event.mouse_x(), event.mouse_y())) { - if (event.is_mouse_move()) { - TakeFocus(); - return true; - } - if (event.is_mouse_left_down()) { + if (event.is_mouse() && box_.Contain(event.mouse().x, event.mouse().y)) { + TakeFocus(); + + if (event.mouse().button == Mouse::Left && + event.mouse().motion == Mouse::Pressed) { on_click(); return true; } diff --git a/src/ftxui/component/checkbox.cpp b/src/ftxui/component/checkbox.cpp index ae3dc0c3..5fe251a7 100644 --- a/src/ftxui/component/checkbox.cpp +++ b/src/ftxui/component/checkbox.cpp @@ -26,15 +26,13 @@ bool CheckBox::OnEvent(Event event) { } bool CheckBox::OnMouseEvent(Event event) { - if (!box_.Contain(event.mouse_x(), event.mouse_y())) + if (!box_.Contain(event.mouse().x, event.mouse().y)) return false; - if (event.is_mouse_move()) { - TakeFocus(); - return true; - } + TakeFocus(); - if (event.is_mouse_left_down()) { + if (event.mouse().button == Mouse::Left && + event.mouse().motion == Mouse::Pressed) { state = !state; on_change(); return true; diff --git a/src/ftxui/component/event.cpp b/src/ftxui/component/event.cpp index dac8951f..2fa0cf05 100644 --- a/src/ftxui/component/event.cpp +++ b/src/ftxui/component/event.cpp @@ -29,56 +29,11 @@ Event Event::Character(wchar_t c) { } // static -Event Event::MouseMove(std::string input, int x, int y) { +Event Event::Mouse(std::string input, struct Mouse mouse) { Event event; event.input_ = std::move(input); - event.type_ = Type::MouseMove; - event.mouse_ = {x, y}; - return event; -} - -// static -Event Event::MouseUp(std::string input, int x, int y) { - Event event; - event.input_ = std::move(input); - event.type_ = Type::MouseUp; - event.mouse_ = {x, y}; - return event; -} - -// static -Event Event::MouseLeftDown(std::string input, int x, int y) { - Event event; - event.input_ = std::move(input); - event.type_ = Type::MouseLeftDown; - event.mouse_ = {x, y}; - return event; -} - -// static -Event Event::MouseLeftMove(std::string input, int x, int y) { - Event event; - event.input_ = std::move(input); - event.type_ = Type::MouseLeftMove; - event.mouse_ = {x, y}; - return event; -} - -// static -Event Event::MouseRightDown(std::string input, int x, int y) { - Event event; - event.input_ = std::move(input); - event.type_ = Type::MouseRightDown; - event.mouse_ = {x, y}; - return event; -} - -// static -Event Event::MouseMiddleMove(std::string input, int x, int y) { - Event event; - event.input_ = std::move(input); - event.type_ = Type::MouseMiddleMove; - event.mouse_ = {x, y}; + event.type_ = Type::Mouse; + event.mouse_ = mouse; return event; } @@ -90,54 +45,15 @@ Event Event::Special(std::string input) { } // static -Event Event::MouseRightMove(std::string input, int x, int y) { - Event event; - event.input_ = std::move(input); - event.type_ = Type::MouseRightMove; - event.mouse_ = {x, y}; - return event; -} - -// static -Event Event::MouseMiddleDown(std::string input, int x, int y) { - Event event; - event.input_ = std::move(input); - event.type_ = Type::MouseMiddleDown; - event.mouse_ = {x, y}; - return event; -} - Event Event::CursorReporting(std::string input, int x, int y) { Event event; event.input_ = std::move(input); event.type_ = Type::CursorReporting; - event.mouse_ = {x, y}; + event.cursor_.x = x; + event.cursor_.y = y; return event; } -bool Event::is_mouse() const { - switch (type_) { - case Type::Unknown: - case Type::Character: - case Type::CursorReporting: - return false; - case Type::MouseMove: - case Type::MouseUp: - case Type::MouseLeftDown: - case Type::MouseLeftMove: - case Type::MouseMiddleDown: - case Type::MouseMiddleMove: - case Type::MouseRightDown: - case Type::MouseRightMove: - return true; - }; -} - -void Event::MoveMouse(int dx, int dy) { - mouse_.x += dx; - mouse_.y += dy; -} - // --- Arrow --- const Event Event::ArrowLeft = Event::Special("\x1B[D"); const Event Event::ArrowRight = Event::Special("\x1B[C"); diff --git a/src/ftxui/component/menu.cpp b/src/ftxui/component/menu.cpp index c626f717..4eccfedf 100644 --- a/src/ftxui/component/menu.cpp +++ b/src/ftxui/component/menu.cpp @@ -61,12 +61,13 @@ bool Menu::OnEvent(Event event) { bool Menu::OnMouseEvent(Event event) { for (int i = 0; i < boxes_.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 = i; - if (event.is_mouse_left_down()) { - TakeFocus(); + if (event.mouse().button == Mouse::Left && + event.mouse().motion == Mouse::Released) { if (selected != i) { selected = i; on_change(); diff --git a/src/ftxui/component/radiobox.cpp b/src/ftxui/component/radiobox.cpp index 7147c862..d3ab38f5 100644 --- a/src/ftxui/component/radiobox.cpp +++ b/src/ftxui/component/radiobox.cpp @@ -56,16 +56,14 @@ bool RadioBox::OnEvent(Event event) { bool RadioBox::OnMouseEvent(Event event) { for (int i = 0; i < boxes_.size(); ++i) { - if (!boxes_[i].Contain(event.mouse_x(), event.mouse_y())) + if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) continue; - if (event.is_mouse_move()) { - focused = i; - TakeFocus(); - return true; - } + focused = i; + TakeFocus(); - if (event.is_mouse_left_down()) { + if (event.mouse().button == Mouse::Left && + event.mouse().motion == Mouse::Pressed) { cursor_position = i; TakeFocus(); if (selected != i) { diff --git a/src/ftxui/component/screen_interactive.cpp b/src/ftxui/component/screen_interactive.cpp index c1494215..d95af0da 100644 --- a/src/ftxui/component/screen_interactive.cpp +++ b/src/ftxui/component/screen_interactive.cpp @@ -146,19 +146,53 @@ void EventListener(std::atomic* quit, Sender out) { #endif -static const char SHOW_CURSOR[] = "\x1B[?25h"; -static const char HIDE_CURSOR[] = "\x1B[?25l"; +const std::string CSI = "\x1b["; -static const char ENABLE_LINE_WRAP[] = "\x1B[7h"; -static const char DISABLE_LINE_WRAP[] = "\x1B[7l"; +// DEC: Digital Equipment Corporation +enum class DECMode { + kLineWrap = 7, + kMouseX10 = 9, + kCursor = 25, + kMouseVt200 = 1000, + kMouseAnyEvent = 1003, + kMouseUtf8 = 1005, + kMouseSgrExtMode = 1006, + kMouseUrxvtMode = 1015, + kMouseSgrPixelsMode = 1016, + kAlternateScreen = 1049, +}; -static const char USE_ALTERNATIVE_SCREEN[] = "\x1B[?1049h"; -static const char USE_NORMAL_SCREEN[] = "\x1B[?1049l"; +// Device Status Report (DSR) { +enum class DSRMode { + kCursor = 6, +}; -static const char ENABLE_MOUSE[] = "\x1B[?1000;1003;1006;1015h"; -static const char DISABLE_MOUSE[] = "\x1B[?1000;1003;1006;1015l"; +const std::string Serialize(std::vector parameters) { + bool first = true; + std::string out; + for (DECMode parameter : parameters) { + if (!first) + out += ";"; + out += std::to_string(int(parameter)); + first = false; + } + return out; +} -static const char REQUEST_CURSOR_LINE[] = "\x1b[6n"; +// DEC Private Mode Set (DECSET) +const std::string Set(std::vector parameters) { + return CSI + "?" + Serialize(parameters) + "h"; +} + +// DEC Private Mode Reset (DECRST) +const std::string Reset(std::vector parameters) { + return CSI + "?" + Serialize(parameters) + "l"; +} + +// Device Status Report (DSR) +const std::string DeviceStatusReport(DSRMode ps) { + return CSI + std::to_string(int(ps)) + "n"; +} using SignalHandler = void(int); std::stack> on_exit_functions; @@ -279,24 +313,44 @@ void ScreenInteractive::Loop(Component* component) { install_signal_handler(SIGWINCH, OnResize); #endif + // Commit state: + auto flush = [&] { + Flush(); + on_exit_functions.push([] { Flush(); }); + }; + + auto enable = [&](std::vector parameters) { + std::cout << Set(parameters); + on_exit_functions.push([=] { std::cout << Reset(parameters); }); + }; + + auto disable = [&](std::vector parameters) { + std::cout << Reset(parameters); + on_exit_functions.push([=] { std::cout << Set(parameters); }); + }; + + flush(); + if (use_alternative_screen_) { - std::cout << USE_ALTERNATIVE_SCREEN; - on_exit_functions.push([] { std::cout << USE_NORMAL_SCREEN; }); + enable({ + DECMode::kAlternateScreen, + }); } - std::cout << ENABLE_MOUSE; - on_exit_functions.push([] { std::cout << DISABLE_MOUSE; }); + // On exit, reset cursor one line after the current drawing. + on_exit_functions.push( + [=] { std::cout << reset_cursor_position << std::endl; }); - // Hide the cursor and show it at exit. - std::cout << HIDE_CURSOR; - std::cout << DISABLE_LINE_WRAP; - Flush(); - on_exit_functions.push([&] { - std::cout << reset_cursor_position; - std::cout << SHOW_CURSOR; - std::cout << ENABLE_LINE_WRAP; - std::cout << std::endl; - Flush(); + disable({ + DECMode::kCursor, + DECMode::kLineWrap, + }); + + enable({ + //DECMode::kMouseVt200, + DECMode::kMouseAnyEvent, + DECMode::kMouseUtf8, + DECMode::kMouseSgrExtMode, }); auto event_listener = @@ -307,8 +361,8 @@ void ScreenInteractive::Loop(Component* component) { if (!event_receiver_->HasPending()) { std::cout << reset_cursor_position << ResetPosition(); static int i = -2; - if (i % 30 == 0) - std::cout << REQUEST_CURSOR_LINE; + if (i % 10 == 0) + std::cout << DeviceStatusReport(DSRMode::kCursor); ++i; Draw(component); std::cout << ToString() << set_cursor_position; @@ -321,13 +375,15 @@ void ScreenInteractive::Loop(Component* component) { break; if (event.is_cursor_reporting()) { - cursor_x_ = event.mouse_y(); - cursor_y_ = event.mouse_x(); + cursor_x_ = event.cursor_x(); + cursor_y_ = event.cursor_y(); continue; } - if (event.is_mouse()) - event.MoveMouse(-cursor_x_, -cursor_y_); + if (event.is_mouse()) { + event.mouse().x -= cursor_x_; + event.mouse().y -= cursor_y_; + } component->OnEvent(event); } diff --git a/src/ftxui/component/terminal_input_parser.cpp b/src/ftxui/component/terminal_input_parser.cpp index c5661544..0864d74e 100644 --- a/src/ftxui/component/terminal_input_parser.cpp +++ b/src/ftxui/component/terminal_input_parser.cpp @@ -36,62 +36,28 @@ void TerminalInputParser::Send(TerminalInputParser::Output output) { return; case DROP: - break; + pending_.clear(); + return; case CHARACTER: out_->Send(Event::Character(std::move(pending_))); - break; + return; case SPECIAL: out_->Send(Event::Special(std::move(pending_))); - break; + return; - case MOUSE_MOVE: - out_->Send( - Event::MouseMove(std::move(pending_), output.mouse.x, output.mouse.y)); - break; - - case MOUSE_UP: - out_->Send( - Event::MouseUp(std::move(pending_), output.mouse.x, output.mouse.y)); - break; - - case MOUSE_LEFT_DOWN: - out_->Send(Event::MouseLeftDown(std::move(pending_), output.mouse.x, - output.mouse.y)); - break; - - case MOUSE_LEFT_MOVE: - out_->Send(Event::MouseLeftMove(std::move(pending_), output.mouse.x, - output.mouse.y)); - break; - - case MOUSE_MIDDLE_DOWN: - out_->Send(Event::MouseMiddleDown(std::move(pending_), output.mouse.x, - output.mouse.y)); - break; - - case MOUSE_MIDDLE_MOVE: - out_->Send(Event::MouseMiddleMove(std::move(pending_), output.mouse.x, - output.mouse.y)); - break; - - case MOUSE_RIGHT_DOWN: - out_->Send(Event::MouseRightDown(std::move(pending_), output.mouse.x, - output.mouse.y)); - break; - - case MOUSE_RIGHT_MOVE: - out_->Send(Event::MouseRightMove(std::move(pending_), output.mouse.x, - output.mouse.y)); - break; + case MOUSE: + out_->Send(Event::Mouse(std::move(pending_), output.mouse)); + return; case CURSOR_REPORTING: - out_->Send(Event::CursorReporting(std::move(pending_), output.mouse.x, - output.mouse.y)); - break; + out_->Send(Event::CursorReporting(std::move(pending_), output.cursor.x, + output.cursor.y)); + return; } - pending_.clear(); + // NOT_REACHED(). + } TerminalInputParser::Output TerminalInputParser::Parse() { @@ -166,12 +132,18 @@ TerminalInputParser::Output TerminalInputParser::ParseDCS() { } TerminalInputParser::Output TerminalInputParser::ParseCSI() { + bool altered = false; int argument; std::vector arguments; while (true) { if (!Eat()) return UNCOMPLETED; + if (Current() == '<') { + altered = true; + continue; + } + if (Current() >= '0' && Current() <= '9') { argument *= 10; argument += int(Current() - '0'); @@ -189,7 +161,9 @@ TerminalInputParser::Output TerminalInputParser::ParseCSI() { argument = 0; switch (Current()) { case 'M': - return ParseMouse(std::move(arguments)); + return ParseMouse(altered, true, std::move(arguments)); + case 'm': + return ParseMouse(altered, false, std::move(arguments)); case 'R': return ParseCursorReporting(std::move(arguments)); default: @@ -219,41 +193,34 @@ TerminalInputParser::Output TerminalInputParser::ParseOSC() { } TerminalInputParser::Output TerminalInputParser::ParseMouse( + bool altered, + bool pressed, std::vector arguments) { if (arguments.size() != 3) return SPECIAL; - switch(arguments[0]) { - case 32: - return Output(MOUSE_LEFT_DOWN, arguments[1], arguments[2]); - case 64: - return Output(MOUSE_LEFT_MOVE, arguments[1], arguments[2]); - case 33: - return Output(MOUSE_MIDDLE_DOWN, arguments[1], arguments[2]); - case 65: - return Output(MOUSE_MIDDLE_MOVE, arguments[1], arguments[2]); + (void)altered; - case 34: - return Output(MOUSE_RIGHT_DOWN, arguments[1], arguments[2]); - case 66: - return Output(MOUSE_RIGHT_MOVE, arguments[1], arguments[2]); - - case 35: - return Output(MOUSE_UP, arguments[1], arguments[2]); - case 67: - return Output(MOUSE_MOVE, arguments[1], arguments[2]); - - default: - return Output(MOUSE_MOVE, arguments[1], arguments[2]); - } - return SPECIAL; + Output output(MOUSE); + output.mouse.button = Mouse::Button((arguments[0] & 3) + // + ((arguments[0] & 64) >> 4)); + output.mouse.motion = Mouse::Motion(pressed); + output.mouse.shift = arguments[0] & 4; + output.mouse.meta = arguments[0] & 8; + output.mouse.control = arguments[0] & 16; + output.mouse.x = arguments[1]; + output.mouse.y = arguments[2]; + return output; } TerminalInputParser::Output TerminalInputParser::ParseCursorReporting( std::vector arguments) { if (arguments.size() != 2) return SPECIAL; - return Output(CURSOR_REPORTING, arguments[0], arguments[1]); + Output output(CURSOR_REPORTING); + output.cursor.y = arguments[0]; + output.cursor.x = arguments[1]; + return output; } } // namespace ftxui diff --git a/src/ftxui/component/terminal_input_parser.hpp b/src/ftxui/component/terminal_input_parser.hpp index bb63ad88..d378694e 100644 --- a/src/ftxui/component/terminal_input_parser.hpp +++ b/src/ftxui/component/terminal_input_parser.hpp @@ -24,31 +24,23 @@ class TerminalInputParser { DROP, CHARACTER, SPECIAL, - MOUSE_UP, - MOUSE_MOVE, - MOUSE_LEFT_DOWN, - MOUSE_LEFT_MOVE, - MOUSE_MIDDLE_DOWN, - MOUSE_MIDDLE_MOVE, - MOUSE_RIGHT_DOWN, - MOUSE_RIGHT_MOVE, + MOUSE, CURSOR_REPORTING, }; - struct Mouse { + struct CursorReporting { int x; int y; - Mouse(int x, int y) : x(x), y(y) {} }; struct Output { Type type; union { Mouse mouse; + CursorReporting cursor; }; Output(Type type) : type(type) {} - Output(Type type, int x, int y) : type(type), mouse(x, y) {} }; void Send(Output type); @@ -58,7 +50,7 @@ class TerminalInputParser { Output ParseDCS(); Output ParseCSI(); Output ParseOSC(); - Output ParseMouse(std::vector arguments); + Output ParseMouse(bool altered, bool pressed, std::vector arguments); Output ParseCursorReporting(std::vector arguments); Sender out_; diff --git a/src/ftxui/component/terminal_input_parser_test.cpp b/src/ftxui/component/terminal_input_parser_test.cpp index 80fbd298..6212a1c4 100644 --- a/src/ftxui/component/terminal_input_parser_test.cpp +++ b/src/ftxui/component/terminal_input_parser_test.cpp @@ -66,22 +66,81 @@ TEST(Event, EscapeKeyEnoughWait) { EXPECT_FALSE(event_receiver->Receive(&received)); } -TEST(Event, GnomeTerminalMouse) { +TEST(Event, MouseLeftClick) { auto event_receiver = MakeReceiver(); { auto parser = TerminalInputParser(event_receiver->MakeSender()); parser.Add('\x1B'); parser.Add('['); - parser.Add('<'); - parser.Add('1'); + parser.Add('3'); + parser.Add('2'); parser.Add(';'); parser.Add('1'); + parser.Add('2'); + parser.Add(';'); + parser.Add('4'); + parser.Add('2'); parser.Add('M'); } Event received; EXPECT_TRUE(event_receiver->Receive(&received)); EXPECT_TRUE(received.is_mouse()); + EXPECT_EQ(Mouse::Left, received.mouse().button); + EXPECT_EQ(12, received.mouse().x); + EXPECT_EQ(42, received.mouse().y); + EXPECT_FALSE(event_receiver->Receive(&received)); +} + +TEST(Event, MouseMiddleClick) { + auto event_receiver = MakeReceiver(); + { + auto parser = TerminalInputParser(event_receiver->MakeSender()); + parser.Add('\x1B'); + parser.Add('['); + parser.Add('3'); + parser.Add('3'); + parser.Add(';'); + parser.Add('1'); + parser.Add('2'); + parser.Add(';'); + parser.Add('4'); + parser.Add('2'); + parser.Add('M'); + } + + Event received; + EXPECT_TRUE(event_receiver->Receive(&received)); + EXPECT_TRUE(received.is_mouse()); + EXPECT_EQ(Mouse::Middle, received.mouse().button); + EXPECT_EQ(12, received.mouse().x); + EXPECT_EQ(42, received.mouse().y); + EXPECT_FALSE(event_receiver->Receive(&received)); +} + +TEST(Event, MouseRightClick) { + auto event_receiver = MakeReceiver(); + { + auto parser = TerminalInputParser(event_receiver->MakeSender()); + parser.Add('\x1B'); + parser.Add('['); + parser.Add('3'); + parser.Add('4'); + parser.Add(';'); + parser.Add('1'); + parser.Add('2'); + parser.Add(';'); + parser.Add('4'); + parser.Add('2'); + parser.Add('M'); + } + + Event received; + EXPECT_TRUE(event_receiver->Receive(&received)); + EXPECT_TRUE(received.is_mouse()); + EXPECT_EQ(Mouse::Right, received.mouse().button); + EXPECT_EQ(12, received.mouse().x); + EXPECT_EQ(42, received.mouse().y); EXPECT_FALSE(event_receiver->Receive(&received)); } diff --git a/src/ftxui/component/toggle.cpp b/src/ftxui/component/toggle.cpp index 525cdedd..5c8b32e0 100644 --- a/src/ftxui/component/toggle.cpp +++ b/src/ftxui/component/toggle.cpp @@ -60,12 +60,13 @@ bool Toggle::OnEvent(Event event) { bool Toggle::OnMouseEvent(Event event) { for (int i = 0; i < boxes_.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 = i; - if (event.is_mouse_left_down()) { + if (event.mouse().button == Mouse::Left && + event.mouse().motion == Mouse::Pressed) { TakeFocus(); if (selected != i) { selected = i; From a27c878a3f2510bbd8daf78229a5e459b42590e8 Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Sun, 25 Apr 2021 16:58:16 +0200 Subject: [PATCH 08/14] Mouse support. Fix & verify Webassembly support. There was some undefined behavior to be fixed in the terminal input parser. The behavior of flush seems to have change. The fix was to invert '\0' and std::flush. --- examples/index.html | 14 +++---- include/ftxui/component/input.hpp | 5 +++ src/ftxui/component/input.cpp | 38 ++++++++++++++++--- src/ftxui/component/screen_interactive.cpp | 4 +- src/ftxui/component/terminal_input_parser.cpp | 11 ++++-- src/ftxui/screen/screen.cpp | 2 +- 6 files changed, 55 insertions(+), 19 deletions(-) diff --git a/examples/index.html b/examples/index.html index fde820ac..461adf29 100644 --- a/examples/index.html +++ b/examples/index.html @@ -10,7 +10,7 @@

FTXUI WebAssembly Example

- FTXUI is a single + FTXUI is a simple C++ library for terminal user interface.

@@ -69,10 +69,8 @@ ]; const url_search_params = new URLSearchParams(window.location.search); - const example_index = url_search_params.get("id") || 16; - const example = example_list[example_index]; - - var select = document.getElementById("selectExample"); + const example = url_search_params.get("file") || "./dom/color_gallery.js" + const select = document.getElementById("selectExample"); for(var i = 0; i < example_list.length; i++) { var opt = example_list[i]; @@ -81,9 +79,10 @@ el.value = opt; select.appendChild(el); } - select.selectedIndex = example_index; + select.selectedIndex = example_list.findIndex(path => path == example) || 0; select.addEventListener("change", () => { - location.href = (location.href).split('?')[0] + "?id=" + select.selectedIndex; + location.href = (location.href).split('?')[0] + "?file=" + + example_list[select.selectedIndex]; }); let stdin_buffer = []; @@ -94,6 +93,7 @@ stdout_buffer = []; let stdout = code => { if (code == 0) { + console.log(code); term.write(new Uint8Array(stdout_buffer)); stdout_buffer = []; } else { diff --git a/include/ftxui/component/input.hpp b/include/ftxui/component/input.hpp index 9b92b835..a55bd307 100644 --- a/include/ftxui/component/input.hpp +++ b/include/ftxui/component/input.hpp @@ -27,6 +27,11 @@ class Input : public Component { // Component implementation. Element Render() override; bool OnEvent(Event) override; + + private: + bool OnMouseEvent(Event); + Box input_box_; + Box cursor_box_; }; } // namespace ftxui diff --git a/src/ftxui/component/input.cpp b/src/ftxui/component/input.cpp index 7a760556..9ca7bcde 100644 --- a/src/ftxui/component/input.cpp +++ b/src/ftxui/component/input.cpp @@ -15,14 +15,15 @@ Element Input::Render() { // Placeholder. if (content.size() == 0) { if (is_focused) - return text(placeholder) | focus | dim | inverted | main_decorator; + return text(placeholder) | focus | dim | inverted | main_decorator | + reflect(input_box_); else - return text(placeholder) | dim | main_decorator; + return text(placeholder) | dim | main_decorator | reflect(input_box_); } // Not focused. if (!is_focused) - return text(content) | main_decorator; + return text(content) | main_decorator | reflect(input_box_); std::wstring part_before_cursor = content.substr(0, cursor_position); std::wstring part_at_cursor = cursor_position < (int)content.size() @@ -37,13 +38,18 @@ Element Input::Render() { return hbox( text(part_before_cursor), - text(part_at_cursor) | underlined | focused, + text(part_at_cursor) | underlined | focused | reflect(cursor_box_), text(part_after_cursor) - ) | flex | inverted | frame | main_decorator; - // clang-format off + ) | flex | inverted | frame | main_decorator | reflect(input_box_); + // clang-format on } + bool Input::OnEvent(Event event) { cursor_position = std::max(0, std::min(content.size(), cursor_position)); + + if (event.is_mouse()) + return OnMouseEvent(event); + std::wstring c; // Backspace. @@ -95,6 +101,26 @@ bool Input::OnEvent(Event event) { return false; } +bool Input::OnMouseEvent(Event event) { + if (!input_box_.Contain(event.mouse().x, event.mouse().y)) + return false; + + TakeFocus(); + + if (event.mouse().button == Mouse::Left && + event.mouse().motion == Mouse::Pressed) { + int new_cursor_position = + cursor_position + event.mouse().x - cursor_box_.x_min; + new_cursor_position = + std::max(0, std::min(content.size(), new_cursor_position)); + if (cursor_position != new_cursor_position) { + cursor_position = new_cursor_position; + on_change(); + } + } + return true; +} + } // namespace ftxui // Copyright 2020 Arthur Sonzogni. All rights reserved. diff --git a/src/ftxui/component/screen_interactive.cpp b/src/ftxui/component/screen_interactive.cpp index d95af0da..385271a0 100644 --- a/src/ftxui/component/screen_interactive.cpp +++ b/src/ftxui/component/screen_interactive.cpp @@ -40,7 +40,7 @@ namespace { void Flush() { // Emscripten doesn't implement flush. We interpret zero as flush. - std::cout << std::flush << (char)0; + std::cout << '\0' << std::flush; } constexpr int timeout_milliseconds = 20; @@ -353,6 +353,8 @@ void ScreenInteractive::Loop(Component* component) { DECMode::kMouseSgrExtMode, }); + flush(); + auto event_listener = std::thread(&EventListener, &quit_, event_receiver_->MakeSender()); diff --git a/src/ftxui/component/terminal_input_parser.cpp b/src/ftxui/component/terminal_input_parser.cpp index 0864d74e..b86d5834 100644 --- a/src/ftxui/component/terminal_input_parser.cpp +++ b/src/ftxui/component/terminal_input_parser.cpp @@ -41,19 +41,23 @@ void TerminalInputParser::Send(TerminalInputParser::Output output) { case CHARACTER: out_->Send(Event::Character(std::move(pending_))); + pending_.clear(); return; case SPECIAL: out_->Send(Event::Special(std::move(pending_))); + pending_.clear(); return; case MOUSE: out_->Send(Event::Mouse(std::move(pending_), output.mouse)); + pending_.clear(); return; case CURSOR_REPORTING: out_->Send(Event::CursorReporting(std::move(pending_), output.cursor.x, output.cursor.y)); + pending_.clear(); return; } // NOT_REACHED(). @@ -133,7 +137,7 @@ TerminalInputParser::Output TerminalInputParser::ParseDCS() { TerminalInputParser::Output TerminalInputParser::ParseCSI() { bool altered = false; - int argument; + int argument = 0; std::vector arguments; while (true) { if (!Eat()) @@ -205,9 +209,8 @@ TerminalInputParser::Output TerminalInputParser::ParseMouse( output.mouse.button = Mouse::Button((arguments[0] & 3) + // ((arguments[0] & 64) >> 4)); output.mouse.motion = Mouse::Motion(pressed); - output.mouse.shift = arguments[0] & 4; - output.mouse.meta = arguments[0] & 8; - output.mouse.control = arguments[0] & 16; + output.mouse.shift = bool(arguments[0] & 4); + output.mouse.meta = bool(arguments[0] & 8); output.mouse.x = arguments[1]; output.mouse.y = arguments[2]; return output; diff --git a/src/ftxui/screen/screen.cpp b/src/ftxui/screen/screen.cpp index d83e4245..3485ee66 100644 --- a/src/ftxui/screen/screen.cpp +++ b/src/ftxui/screen/screen.cpp @@ -184,7 +184,7 @@ std::string Screen::ToString() { } void Screen::Print() { - std::cout << ToString() << std::flush << (char)0; + std::cout << ToString() << '\0' << std::flush; } /// @brief Access a character a given position. From 5322e5a68357af41e940d69b732727e96e98082c Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Sun, 25 Apr 2021 17:04:26 +0200 Subject: [PATCH 09/14] Increase version to 0.4.x Version 0.4 bring mouse support. See https://github.com/ArthurSonzogni/FTXUI/issues/7 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a65cfd39..5b2d86b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ endif() project(ftxui LANGUAGES CXX - VERSION 0.3.${git_version} + VERSION 0.4.${git_version} ) option(FTXUI_BUILD_EXAMPLES "Set to ON to build examples" ON) From f0626342260ada379cd87cd26380222275c929e2 Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Sun, 25 Apr 2021 17:28:16 +0200 Subject: [PATCH 10/14] Fix compilation errors on WebAssembly and Windows. --- CMakeLists.txt | 2 +- src/ftxui/dom/reflect.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b2d86b7..24214cf5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -201,7 +201,7 @@ if (FTXUI_BUILD_TESTS AND ${CMAKE_VERSION} VERSION_GREATER "3.11.4") FetchContent_Declare( googletest GIT_REPOSITORY "https://github.com/google/googletest" - GIT_TAG release-1.10.0 + GIT_TAG 23ef29555ef4789f555f1ba8c51b4c52975f0907 ) FetchContent_GetProperties(googletest) diff --git a/src/ftxui/dom/reflect.cpp b/src/ftxui/dom/reflect.cpp index 10e71947..0ce40e43 100644 --- a/src/ftxui/dom/reflect.cpp +++ b/src/ftxui/dom/reflect.cpp @@ -5,8 +5,6 @@ namespace ftxui { -Box box; - // Helper class. class Reflect : public Node { public: From 7d132c6225938b39dd239d61ef137d05dd3662c3 Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Sun, 25 Apr 2021 17:37:11 +0200 Subject: [PATCH 11/14] Fix webassembly workflow. --- .github/workflows/linux-emscripten.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/linux-emscripten.yaml b/.github/workflows/linux-emscripten.yaml index a2b9e40f..64b5f511 100644 --- a/.github/workflows/linux-emscripten.yaml +++ b/.github/workflows/linux-emscripten.yaml @@ -17,5 +17,4 @@ jobs: mkdir build; cd build; emcmake cmake .. - -DFTXUI_BUILD_TESTS=ON; cmake --build . --config Release; From 0af8201023eab435d13ef9cb210844a3bf8bf46e Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Thu, 29 Apr 2021 00:18:58 +0200 Subject: [PATCH 12/14] Add the slider component. --- CMakeLists.txt | 4 +- examples/component/CMakeLists.txt | 3 +- examples/component/slider.cpp | 79 ++++++++++++++++++++++++++ include/ftxui/component/component.hpp | 3 + include/ftxui/component/slider.hpp | 25 +++++++++ src/ftxui/component/slider.cpp | 80 +++++++++++++++++++++++++++ 6 files changed, 192 insertions(+), 2 deletions(-) create mode 100644 examples/component/slider.cpp create mode 100644 include/ftxui/component/slider.hpp create mode 100644 src/ftxui/component/slider.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 24214cf5..3b792040 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,6 +87,7 @@ add_library(component include/ftxui/component/radiobox.hpp include/ftxui/component/receiver.hpp include/ftxui/component/screen_interactive.hpp + include/ftxui/component/slider.hpp include/ftxui/component/toggle.hpp src/ftxui/component/button.cpp src/ftxui/component/checkbox.cpp @@ -98,9 +99,10 @@ add_library(component src/ftxui/component/radiobox.cpp src/ftxui/component/radiobox.cpp src/ftxui/component/screen_interactive.cpp - src/ftxui/component/toggle.cpp + src/ftxui/component/slider.cpp src/ftxui/component/terminal_input_parser.cpp src/ftxui/component/terminal_input_parser.hpp + src/ftxui/component/toggle.cpp ) add_library(ftxui::screen ALIAS screen) diff --git a/examples/component/CMakeLists.txt b/examples/component/CMakeLists.txt index d20f8995..07dc0b31 100644 --- a/examples/component/CMakeLists.txt +++ b/examples/component/CMakeLists.txt @@ -13,9 +13,10 @@ example(input) example(menu) example(menu2) example(menu_style) +example(modal_dialog) example(radiobox) example(radiobox_in_frame) +example(slider) example(tab_horizontal) example(tab_vertical) example(toggle) -example(modal_dialog) diff --git a/examples/component/slider.cpp b/examples/component/slider.cpp new file mode 100644 index 00000000..65cb068d --- /dev/null +++ b/examples/component/slider.cpp @@ -0,0 +1,79 @@ +#include "ftxui/component/slider.hpp" +#include "ftxui/component/container.hpp" +#include "ftxui/component/screen_interactive.hpp" +#include "ftxui/component/toggle.hpp" +#include "ftxui/screen/string.hpp" + +using namespace ftxui; + +Element ColorTile(int red, int green, int blue) { + return text(L"") + | size(WIDTH, GREATER_THAN, 14) + | size(HEIGHT, GREATER_THAN, 7) + | bgcolor(Color::RGB(red, green, blue)); +} + +Element ColorString(int red, int green, int blue) { + return text(L"RGB = (" + // + std::to_wstring(red) + L"," + // + std::to_wstring(green) + L"," + // + std::to_wstring(blue) + L")" // + ); +} + +class MyComponent : public Component { + public: + MyComponent(int* red, int* green, int* blue, std::function quit) + : red_(red), green_(green), blue_(blue), quit_(quit) { + Add(&container_); + container_.Add(slider_red_.get()); + container_.Add(slider_green_.get()); + container_.Add(slider_blue_.get()); + } + + Element Render() { + return hbox({ + ColorTile(*red_, *green_, *blue_), + separator(), + vbox({ + slider_red_->Render(), + separator(), + slider_green_->Render(), + separator(), + slider_blue_->Render(), + separator(), + ColorString(*red_, *green_, *blue_), + }) | xflex, + }) | + border | size(WIDTH, LESS_THAN, 80); + } + + bool OnEvent(Event event) { + if (event == Event::Return || event == Event::Escape) + quit_(); + return Component::OnEvent(event); + } + + private: + int* red_; + int* green_; + int* blue_; + Container container_ = Container::Vertical(); + ComponentPtr slider_red_ = Slider(L"Red :", red_, 0, 255, 1); + ComponentPtr slider_green_ = Slider(L"Green:", green_, 0, 255, 1); + ComponentPtr slider_blue_ = Slider(L"Blue :", blue_, 0, 255, 1); + std::function quit_; +}; + +int main(int argc, const char* argv[]) { + auto screen = ScreenInteractive::TerminalOutput(); + int red = 128; + int green = 25; + int blue = 100; + auto component = MyComponent(&red, &green, &blue, screen.ExitLoopClosure()); + screen.Loop(&component); +} + +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. diff --git a/include/ftxui/component/component.hpp b/include/ftxui/component/component.hpp index 2b7af38e..fcaf3f9c 100644 --- a/include/ftxui/component/component.hpp +++ b/include/ftxui/component/component.hpp @@ -1,6 +1,7 @@ #ifndef FTXUI_COMPONENT_COMPONENT_HPP #define FTXUI_COMPONENT_COMPONENT_HPP +#include #include "ftxui/component/event.hpp" #include "ftxui/dom/elements.hpp" @@ -60,6 +61,8 @@ class Component { std::vector children_; }; +using ComponentPtr = std::unique_ptr; + } // namespace ftxui #endif /* end of include guard: FTXUI_COMPONENT_COMPONENT_HPP */ diff --git a/include/ftxui/component/slider.hpp b/include/ftxui/component/slider.hpp new file mode 100644 index 00000000..35a139de --- /dev/null +++ b/include/ftxui/component/slider.hpp @@ -0,0 +1,25 @@ +#ifndef FTXUI_COMPONENT_SLIDER_HPP +#define FTXUI_COMPONENT_SLIDER_HPP + +#include +#include "ftxui/component/component.hpp" + +namespace ftxui { +// ComponentPtr Slider(std::string label, +// float* value, +// float min = 0.f, +// float max = 100.f, +// float increment = (max - min) * 0.05f); + +ComponentPtr Slider(std::wstring label, + int* value, + int min, + int max, + int increment); +} // namespace ftxui + +#endif /* end of include guard: FTXUI_COMPONENT_SLIDER_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/src/ftxui/component/slider.cpp b/src/ftxui/component/slider.cpp new file mode 100644 index 00000000..894f9ee1 --- /dev/null +++ b/src/ftxui/component/slider.cpp @@ -0,0 +1,80 @@ +#include "ftxui/component/slider.hpp" + +namespace ftxui { +class SliderInt : public Component { + public: + SliderInt(std::wstring label, int* value, int min, int max, int increment) + : label_(label), + value_(value), + min_(min), + max_(max), + increment_(increment) {} + + Element Render() { + auto gauge_color = + Focused() ? color(Color::GrayLight) : color(Color::GrayDark); + float percent = float(*value_ - min_) / float(max_ - min_); + return hbox({ + text(label_) | dim | vcenter, + hbox({ + text(L"["), + gauge(percent) | underlined | xflex | reflect(gauge_box_), + text(L"]"), + }) | xflex, + }) | + gauge_color | xflex | reflect(box_); + } + + bool OnEvent(Event event) final { + if (event.is_mouse()) + return OnMouseEvent(event); + + if (event == Event::ArrowLeft || event == Event::Character('h')) { + *value_ -= increment_; + *value_ = std::max(*value_, min_); + return true; + } + + if (event == Event::ArrowRight || event == Event::Character('l')) { + *value_ += increment_; + *value_ = std::min(*value_, max_); + return true; + } + + return Component::OnEvent(event); + } + + bool OnMouseEvent(Event event) { + if (!box_.Contain(event.mouse().x, event.mouse().y)) + return false; + TakeFocus(); + if (!gauge_box_.Contain(event.mouse().x, event.mouse().y)) + return false; + if (event.mouse().button == Mouse::Left && + event.mouse().motion == Mouse::Pressed) { + *value_ = min_ + (event.mouse().x - gauge_box_.x_min) * (max_ - min_) / + (gauge_box_.x_max - gauge_box_.x_min); + } + return true; + } + + private: + std::wstring label_; + int* value_; + int min_; + int max_; + int increment_ = 1; + Box box_; + Box gauge_box_; +}; + +ComponentPtr Slider(std::wstring label, + int* value, + int min, + int max, + int increment) { + return std::make_unique(std::move(label), value, min, max, + increment); +} + +} // namespace ftxui From eb399d20c52d83f815176b85706ba7f6cc2ddba6 Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Sat, 1 May 2021 18:13:56 +0200 Subject: [PATCH 13/14] Capture mouse for the slider component. --- CMakeLists.txt | 1 + examples/component/gallery.cpp | 33 +++++++-- include/ftxui/component/captured_mouse.hpp | 14 ++++ include/ftxui/component/component.hpp | 6 +- include/ftxui/component/event.hpp | 7 ++ .../ftxui/component/screen_interactive.hpp | 4 + include/ftxui/component/slider.hpp | 11 ++- src/ftxui/component/button.cpp | 4 + src/ftxui/component/checkbox.cpp | 3 + src/ftxui/component/input.cpp | 3 + src/ftxui/component/menu.cpp | 5 ++ src/ftxui/component/radiobox.cpp | 5 ++ src/ftxui/component/screen_interactive.cpp | 20 +++++ src/ftxui/component/slider.cpp | 73 +++++++++++++------ src/ftxui/component/toggle.cpp | 3 + 15 files changed, 157 insertions(+), 35 deletions(-) create mode 100644 include/ftxui/component/captured_mouse.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b792040..c6182a06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,6 +77,7 @@ add_library(dom add_library(component include/ftxui/component/button.hpp + include/ftxui/component/captured_mouse.hpp include/ftxui/component/checkbox.hpp include/ftxui/component/component.hpp include/ftxui/component/container.hpp diff --git a/examples/component/gallery.cpp b/examples/component/gallery.cpp index 54f4d6cc..9bd5c868 100644 --- a/examples/component/gallery.cpp +++ b/examples/component/gallery.cpp @@ -5,6 +5,7 @@ #include "ftxui/component/menu.hpp" #include "ftxui/component/radiobox.hpp" #include "ftxui/component/screen_interactive.hpp" +#include "ftxui/component/slider.hpp" #include "ftxui/component/toggle.hpp" using namespace ftxui; @@ -20,6 +21,13 @@ class MyComponent : public Component { Input input; Button button; + int slider_value_1_ = 12; + int slider_value_2_ = 56; + int slider_value_3_ = 128; + ComponentPtr slider_1_ = Slider(L"R:", &slider_value_1_, 0, 256, 1); + ComponentPtr slider_2_ = Slider(L"G:", &slider_value_2_, 0, 256, 1); + ComponentPtr slider_3_ = Slider(L"B:", &slider_value_3_, 0, 256, 1); + public: MyComponent() { Add(&container); @@ -54,17 +62,25 @@ class MyComponent : public Component { input.placeholder = L"Input placeholder"; container.Add(&input); + container.Add(slider_1_.get()); + container.Add(slider_2_.get()); + container.Add(slider_3_.get()); + button.label = L"Quit"; button.on_click = [&] { on_quit(); }; container.Add(&button); } - Element Render(std::wstring name, Component& component) { + Element Render(std::wstring name, Element element) { return hbox({ text(name) | size(WIDTH, EQUAL, 8), separator(), - component.Render(), - }); + element | xflex, + }) | xflex; + } + + Element Render(std::wstring name, Component& component) { + return Render(name, component.Render()); } Element Render() override { @@ -78,11 +94,18 @@ class MyComponent : public Component { separator(), Render(L"radiobox", radiobox), separator(), - Render(L"input", input) | size(WIDTH, LESS_THAN, 30), + Render(L"input", input) | size(WIDTH, LESS_THAN, 50), + separator(), + Render(L"slider", // + vbox({ + slider_1_->Render(), + slider_2_->Render(), + slider_3_->Render(), + })), separator(), Render(L"button", button), }) | - border; + xflex | size(WIDTH, GREATER_THAN, 40) | border; } std::function on_quit = [] {}; diff --git a/include/ftxui/component/captured_mouse.hpp b/include/ftxui/component/captured_mouse.hpp new file mode 100644 index 00000000..b76ac10f --- /dev/null +++ b/include/ftxui/component/captured_mouse.hpp @@ -0,0 +1,14 @@ +#ifndef FTXUI_CAPTURED_MOUSE_HPP +#define FTXUI_CAPTURED_MOUSE_HPP + +#include + +namespace ftxui { +class CapturedMouseInterface { + public: + virtual ~CapturedMouseInterface() {} +}; +using CapturedMouse = std::unique_ptr; +} // namespace ftxui + +#endif /* end of include guard: FTXUI_CAPTURED_MOUSE_HPP */ diff --git a/include/ftxui/component/component.hpp b/include/ftxui/component/component.hpp index fcaf3f9c..5a422163 100644 --- a/include/ftxui/component/component.hpp +++ b/include/ftxui/component/component.hpp @@ -52,13 +52,13 @@ class Component { // Configure all the ancestors to give focus to this component. void TakeFocus(); + protected: + std::vector children_; + private: Component* parent_ = nullptr; void Detach(); void Attach(Component* parent); - - protected: - std::vector children_; }; using ComponentPtr = std::unique_ptr; diff --git a/include/ftxui/component/event.hpp b/include/ftxui/component/event.hpp index bb87c6a1..6295c919 100644 --- a/include/ftxui/component/event.hpp +++ b/include/ftxui/component/event.hpp @@ -10,6 +10,8 @@ namespace ftxui { +class ScreenInteractive; + /// @brief Represent an event. It can be key press event, a terminal resize, or /// more ... /// @@ -65,6 +67,9 @@ struct Event { const std::string& input() const { return input_; } + ScreenInteractive* screen() { return screen_; } + void SetScreen(ScreenInteractive* screen) { screen_ = screen; } + bool operator==(const Event& other) const { return input_ == other.input_; } //--- State section ---------------------------------------------------------- @@ -88,6 +93,8 @@ struct Event { struct Cursor cursor_; }; std::string input_; + + ScreenInteractive* screen_; }; diff --git a/include/ftxui/component/screen_interactive.hpp b/include/ftxui/component/screen_interactive.hpp index 8f5903a4..c61132c0 100644 --- a/include/ftxui/component/screen_interactive.hpp +++ b/include/ftxui/component/screen_interactive.hpp @@ -9,6 +9,7 @@ #include #include +#include "ftxui/component/captured_mouse.hpp" #include "ftxui/component/event.hpp" #include "ftxui/screen/screen.hpp" @@ -27,6 +28,7 @@ class ScreenInteractive : public Screen { std::function ExitLoopClosure(); void PostEvent(Event event); + CapturedMouse CaptureMouse(); private: void Draw(Component* component); @@ -55,6 +57,8 @@ class ScreenInteractive : public Screen { int cursor_x_ = 0; int cursor_y_ = 0; + + bool mouse_captured = false; }; } // namespace ftxui diff --git a/include/ftxui/component/slider.hpp b/include/ftxui/component/slider.hpp index 35a139de..f9bff719 100644 --- a/include/ftxui/component/slider.hpp +++ b/include/ftxui/component/slider.hpp @@ -11,11 +11,14 @@ namespace ftxui { // float max = 100.f, // float increment = (max - min) * 0.05f); +template // T = {int, float} ComponentPtr Slider(std::wstring label, - int* value, - int min, - int max, - int increment); + T* value, + T min, + T max, + T increment); + + } // namespace ftxui #endif /* end of include guard: FTXUI_COMPONENT_SLIDER_HPP */ diff --git a/src/ftxui/component/button.cpp b/src/ftxui/component/button.cpp index 4da42ddb..3ea1b777 100644 --- a/src/ftxui/component/button.cpp +++ b/src/ftxui/component/button.cpp @@ -1,4 +1,5 @@ #include "ftxui/component/button.hpp" +#include "ftxui/component/screen_interactive.hpp" #include @@ -11,6 +12,9 @@ Element Button::Render() { bool Button::OnEvent(Event event) { if (event.is_mouse() && box_.Contain(event.mouse().x, event.mouse().y)) { + if (!event.screen()->CaptureMouse()) + return false; + TakeFocus(); if (event.mouse().button == Mouse::Left && diff --git a/src/ftxui/component/checkbox.cpp b/src/ftxui/component/checkbox.cpp index 5fe251a7..8c04a085 100644 --- a/src/ftxui/component/checkbox.cpp +++ b/src/ftxui/component/checkbox.cpp @@ -1,4 +1,5 @@ #include "ftxui/component/checkbox.hpp" +#include "ftxui/component/screen_interactive.hpp" #include @@ -26,6 +27,8 @@ bool CheckBox::OnEvent(Event event) { } bool CheckBox::OnMouseEvent(Event event) { + if (!event.screen()->CaptureMouse()) + return false; if (!box_.Contain(event.mouse().x, event.mouse().y)) return false; diff --git a/src/ftxui/component/input.cpp b/src/ftxui/component/input.cpp index 9ca7bcde..d39ec1bb 100644 --- a/src/ftxui/component/input.cpp +++ b/src/ftxui/component/input.cpp @@ -1,4 +1,5 @@ #include "ftxui/component/input.hpp" +#include "ftxui/component/screen_interactive.hpp" #include @@ -102,6 +103,8 @@ bool Input::OnEvent(Event event) { } bool Input::OnMouseEvent(Event event) { + if (!event.screen()->CaptureMouse()) + return false; if (!input_box_.Contain(event.mouse().x, event.mouse().y)) return false; diff --git a/src/ftxui/component/menu.cpp b/src/ftxui/component/menu.cpp index 4eccfedf..44f5f364 100644 --- a/src/ftxui/component/menu.cpp +++ b/src/ftxui/component/menu.cpp @@ -1,4 +1,5 @@ #include "ftxui/component/menu.hpp" +#include "ftxui/component/screen_interactive.hpp" #include #include @@ -27,6 +28,8 @@ Element Menu::Render() { } bool Menu::OnEvent(Event event) { + if (!event.screen()->CaptureMouse()) + return false; if (event.is_mouse()) return OnMouseEvent(event); @@ -60,6 +63,8 @@ bool Menu::OnEvent(Event event) { } bool Menu::OnMouseEvent(Event event) { + if (!event.screen()->CaptureMouse()) + return false; for (int i = 0; i < boxes_.size(); ++i) { if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) continue; diff --git a/src/ftxui/component/radiobox.cpp b/src/ftxui/component/radiobox.cpp index d3ab38f5..7c50655f 100644 --- a/src/ftxui/component/radiobox.cpp +++ b/src/ftxui/component/radiobox.cpp @@ -1,4 +1,5 @@ #include "ftxui/component/radiobox.hpp" +#include "ftxui/component/screen_interactive.hpp" #include #include @@ -23,6 +24,8 @@ Element RadioBox::Render() { } bool RadioBox::OnEvent(Event event) { + if (!event.screen()->CaptureMouse()) + return false; if (event.is_mouse()) return OnMouseEvent(event); @@ -55,6 +58,8 @@ bool RadioBox::OnEvent(Event event) { } bool RadioBox::OnMouseEvent(Event event) { + if (!event.screen()->CaptureMouse()) + return false; for (int i = 0; i < boxes_.size(); ++i) { if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) continue; diff --git a/src/ftxui/component/screen_interactive.cpp b/src/ftxui/component/screen_interactive.cpp index 385271a0..95cc26cc 100644 --- a/src/ftxui/component/screen_interactive.cpp +++ b/src/ftxui/component/screen_interactive.cpp @@ -9,6 +9,7 @@ #include #include +#include "ftxui/component/captured_mouse.hpp" #include "ftxui/component/component.hpp" #include "ftxui/component/terminal_input_parser.hpp" #include "ftxui/screen/string.hpp" @@ -216,6 +217,16 @@ void OnResize(int /* signal */) { on_resize(); } +class CapturedMouseImpl : public CapturedMouseInterface { + public: + CapturedMouseImpl(std::function callback) + : callback_(callback) {} + ~CapturedMouseImpl() override { callback_(); } + + private: + std::function callback_; +}; + } // namespace ScreenInteractive::ScreenInteractive(int dimx, @@ -256,6 +267,14 @@ void ScreenInteractive::PostEvent(Event event) { event_sender_->Send(event); } +CapturedMouse ScreenInteractive::CaptureMouse() { + if (mouse_captured) + return nullptr; + mouse_captured = true; + return std::make_unique( + [this] { mouse_captured = false; }); +} + void ScreenInteractive::Loop(Component* component) { // Install a SIGINT handler and restore the old handler on exit. auto old_sigint_handler = std::signal(SIGINT, OnExit); @@ -387,6 +406,7 @@ void ScreenInteractive::Loop(Component* component) { event.mouse().y -= cursor_y_; } + event.SetScreen(this); component->OnEvent(event); } diff --git a/src/ftxui/component/slider.cpp b/src/ftxui/component/slider.cpp index 894f9ee1..8ddb4fb4 100644 --- a/src/ftxui/component/slider.cpp +++ b/src/ftxui/component/slider.cpp @@ -1,9 +1,13 @@ #include "ftxui/component/slider.hpp" +#include "ftxui/component/captured_mouse.hpp" +#include "ftxui/component/screen_interactive.hpp" namespace ftxui { -class SliderInt : public Component { + +template +class SliderImpl : public Component { public: - SliderInt(std::wstring label, int* value, int min, int max, int increment) + SliderImpl(std::wstring label, T* value, T min, T max, T increment) : label_(label), value_(value), min_(min), @@ -45,36 +49,59 @@ class SliderInt : public Component { } bool OnMouseEvent(Event event) { - if (!box_.Contain(event.mouse().x, event.mouse().y)) - return false; - TakeFocus(); - if (!gauge_box_.Contain(event.mouse().x, event.mouse().y)) - return false; - if (event.mouse().button == Mouse::Left && - event.mouse().motion == Mouse::Pressed) { - *value_ = min_ + (event.mouse().x - gauge_box_.x_min) * (max_ - min_) / - (gauge_box_.x_max - gauge_box_.x_min); + if (captured_mouse_ && event.mouse().motion == Mouse::Released) { + captured_mouse_ = nullptr; + return true; } - return true; + + if (box_.Contain(event.mouse().x, event.mouse().y) && + event.screen()->CaptureMouse()) { + TakeFocus(); + } + + if (event.mouse().button == Mouse::Left && + event.mouse().motion == Mouse::Pressed && + gauge_box_.Contain(event.mouse().x, event.mouse().y) && + !captured_mouse_) { + captured_mouse_ = event.screen()->CaptureMouse(); + } + + if (captured_mouse_) { + *value_ = min_ + (event.mouse().x - gauge_box_.x_min) * (max_ - min_) / + (gauge_box_.x_max - gauge_box_.x_min); + *value_ = std::max(min_, std::min(max_, *value_)); + return true; + } + return false; } private: std::wstring label_; - int* value_; - int min_; - int max_; - int increment_ = 1; + T* value_; + T min_; + T max_; + T increment_ = 1; Box box_; Box gauge_box_; + CapturedMouse captured_mouse_; }; -ComponentPtr Slider(std::wstring label, - int* value, - int min, - int max, - int increment) { - return std::make_unique(std::move(label), value, min, max, - increment); +template +ComponentPtr Slider(std::wstring label, T* value, T min, T max, T increment) { + return std::make_unique>(std::move(label), value, min, max, + increment); } +template ComponentPtr Slider(std::wstring label, + int* value, + int min, + int max, + int increment); + +template ComponentPtr Slider(std::wstring label, + float* value, + float min, + float max, + float increment); + } // namespace ftxui diff --git a/src/ftxui/component/toggle.cpp b/src/ftxui/component/toggle.cpp index 5c8b32e0..89360966 100644 --- a/src/ftxui/component/toggle.cpp +++ b/src/ftxui/component/toggle.cpp @@ -1,4 +1,5 @@ #include "ftxui/component/toggle.hpp" +#include "ftxui/component/screen_interactive.hpp" #include @@ -59,6 +60,8 @@ bool Toggle::OnEvent(Event event) { } bool Toggle::OnMouseEvent(Event event) { + if (!event.screen()->CaptureMouse()) + return false; for (int i = 0; i < boxes_.size(); ++i) { if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) continue; From 155758c0731df5ede369d9e8b9ed0b1fca04d946 Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Sat, 1 May 2021 20:40:35 +0200 Subject: [PATCH 14/14] Use IWYU. --- .github/workflows/linux-emscripten.yaml | 2 +- CMakeLists.txt | 8 +++ doc/example_list.md | 1 + examples/component/button.cpp | 14 +++-- examples/component/checkbox.cpp | 7 ++- examples/component/checkbox_in_frame.cpp | 19 ++++--- examples/component/gallery.cpp | 35 +++++++----- examples/component/homescreen.cpp | 29 ++++++---- examples/component/input.cpp | 8 +-- examples/component/menu.cpp | 13 ++--- examples/component/menu2.cpp | 17 +++--- examples/component/menu_style.cpp | 26 ++++++--- examples/component/modal_dialog.cpp | 15 ++++-- examples/component/radiobox.cpp | 5 +- examples/component/radiobox_in_frame.cpp | 17 +++--- examples/component/slider.cpp | 23 ++++---- examples/component/tab_horizontal.cpp | 17 +++--- examples/component/tab_vertical.cpp | 14 ++--- examples/component/toggle.cpp | 11 ++-- examples/dom/border.cpp | 7 +-- examples/dom/color_gallery.cpp | 10 ++-- examples/dom/color_info_palette256.cpp | 11 ++-- examples/dom/color_truecolor_HSV.cpp | 9 ++-- examples/dom/color_truecolor_RGB.cpp | 9 ++-- examples/dom/dbox.cpp | 5 +- examples/dom/gauge.cpp | 4 ++ examples/dom/graph.cpp | 8 ++- examples/dom/hflow.cpp | 6 ++- examples/dom/html_like.cpp | 6 ++- examples/dom/package_manager.cpp | 7 +++ examples/dom/paragraph.cpp | 7 ++- examples/dom/separator.cpp | 5 +- examples/dom/size.cpp | 7 ++- examples/dom/spinner.cpp | 6 +++ examples/dom/style_blink.cpp | 5 +- examples/dom/style_bold.cpp | 5 +- examples/dom/style_color.cpp | 6 ++- examples/dom/style_dim.cpp | 5 +- examples/dom/style_gallery.cpp | 6 ++- examples/dom/style_inverted.cpp | 5 +- examples/dom/style_underlined.cpp | 5 +- examples/dom/vbox_hbox.cpp | 6 ++- examples/dom/window.cpp | 6 ++- examples/util/print_key_press.cpp | 22 +++++--- include/ftxui/component/button.hpp | 5 ++ include/ftxui/component/captured_mouse.hpp | 4 ++ include/ftxui/component/checkbox.hpp | 5 +- include/ftxui/component/component.hpp | 11 ++-- include/ftxui/component/container.hpp | 2 + include/ftxui/component/event.hpp | 18 +++---- include/ftxui/component/input.hpp | 4 ++ include/ftxui/component/menu.hpp | 4 ++ include/ftxui/component/mouse.hpp | 3 ++ include/ftxui/component/radiobox.hpp | 6 ++- include/ftxui/component/receiver.hpp | 11 ++-- .../ftxui/component/screen_interactive.hpp | 14 +++-- include/ftxui/component/slider.hpp | 9 +--- include/ftxui/component/toggle.hpp | 5 +- include/ftxui/dom/elements.hpp | 2 +- include/ftxui/dom/node.hpp | 10 ++-- include/ftxui/dom/take_any_args.hpp | 1 + include/ftxui/screen/color.hpp | 4 +- include/ftxui/screen/color_info.hpp | 1 + iwyu.imp | 8 +++ src/ftxui/component/button.cpp | 12 +++-- src/ftxui/component/checkbox.cpp | 12 +++-- src/ftxui/component/component.cpp | 23 +++++++- src/ftxui/component/container.cpp | 2 + src/ftxui/component/container_test.cpp | 8 ++- src/ftxui/component/event.cpp | 2 +- src/ftxui/component/input.cpp | 8 +-- src/ftxui/component/menu.cpp | 13 +++-- src/ftxui/component/radiobox.cpp | 17 ++++-- src/ftxui/component/radiobox_test.cpp | 8 ++- src/ftxui/component/receiver_test.cpp | 10 ++-- src/ftxui/component/screen_interactive.cpp | 53 ++++++++++--------- src/ftxui/component/slider.cpp | 18 +++++-- src/ftxui/component/terminal_input_parser.cpp | 8 ++- src/ftxui/component/terminal_input_parser.hpp | 9 ++-- .../component/terminal_input_parser_test.cpp | 8 +-- src/ftxui/component/toggle.cpp | 13 +++-- src/ftxui/component/toggle_test.cpp | 8 ++- src/ftxui/dom/blink.cpp | 5 ++ src/ftxui/dom/bold.cpp | 5 ++ src/ftxui/dom/border.cpp | 13 +++-- src/ftxui/dom/clear_under.cpp | 5 ++ src/ftxui/dom/color.cpp | 5 ++ src/ftxui/dom/composite_decorator.cpp | 2 +- src/ftxui/dom/dbox.cpp | 11 ++-- src/ftxui/dom/dim.cpp | 5 ++ src/ftxui/dom/flex.cpp | 5 ++ src/ftxui/dom/frame.cpp | 14 +++-- src/ftxui/dom/gauge.cpp | 6 ++- src/ftxui/dom/gauge_test.cpp | 12 +++-- src/ftxui/dom/graph.cpp | 10 +++- src/ftxui/dom/hbox.cpp | 11 ++-- src/ftxui/dom/hbox_test.cpp | 13 +++-- src/ftxui/dom/hflow.cpp | 11 ++-- src/ftxui/dom/inverted.cpp | 5 ++ src/ftxui/dom/node.cpp | 3 ++ src/ftxui/dom/node_decorator.cpp | 5 ++ src/ftxui/dom/node_decorator.hpp | 5 +- src/ftxui/dom/paragraph.cpp | 1 + src/ftxui/dom/reflect.cpp | 6 ++- src/ftxui/dom/separator.cpp | 4 ++ src/ftxui/dom/size.cpp | 12 +++-- src/ftxui/dom/spinner.cpp | 6 ++- src/ftxui/dom/text.cpp | 14 +++-- src/ftxui/dom/text_test.cpp | 12 +++-- src/ftxui/dom/underlined.cpp | 5 ++ src/ftxui/dom/util.cpp | 5 +- src/ftxui/dom/vbox.cpp | 12 +++-- src/ftxui/dom/vbox_test.cpp | 14 +++-- src/ftxui/screen/color.cpp | 3 -- src/ftxui/screen/color_info.cpp | 1 + src/ftxui/screen/screen.cpp | 22 ++++---- src/ftxui/screen/terminal.cpp | 13 ++--- src/ftxui/screen/wcwidth.cpp | 2 +- tools/iwyu.sh | 11 ++++ 119 files changed, 770 insertions(+), 342 deletions(-) create mode 100644 iwyu.imp create mode 100755 tools/iwyu.sh diff --git a/.github/workflows/linux-emscripten.yaml b/.github/workflows/linux-emscripten.yaml index 64b5f511..1c60d402 100644 --- a/.github/workflows/linux-emscripten.yaml +++ b/.github/workflows/linux-emscripten.yaml @@ -16,5 +16,5 @@ jobs: run: > mkdir build; cd build; - emcmake cmake .. + emcmake cmake ..; cmake --build . --config Release; diff --git a/CMakeLists.txt b/CMakeLists.txt index c6182a06..e6fc342e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,6 +112,14 @@ add_library(ftxui::component ALIAS component) target_link_libraries(dom PUBLIC screen) target_link_libraries(component PUBLIC dom Threads::Threads) + find_program(iwyu_path NAMES include-what-you-use iwyu) + if(iwyu_path) + set_property(TARGET ${lib} + PROPERTY ${iwyu_path} -Xiwyu + --mapping_file ${CMAKE_CURRENT_SOURCE_DIR}/iwyu.impl + ) + endif() + foreach(lib screen dom component) target_include_directories(${lib} diff --git a/doc/example_list.md b/doc/example_list.md index 3b089bc0..efddeab1 100644 --- a/doc/example_list.md +++ b/doc/example_list.md @@ -30,6 +30,7 @@ @example ./examples/component/checkbox_in_frame.cpp @example ./examples/component/menu2.cpp @example ./examples/component/tab_horizontal.cpp +@example ./examples/component/slider.cpp @example ./examples/component/input.cpp @example ./examples/component/homescreen.cpp @example ./examples/component/radiobox.cpp diff --git a/examples/component/button.cpp b/examples/component/button.cpp index d38f4c17..dc3ceaf1 100644 --- a/examples/component/button.cpp +++ b/examples/component/button.cpp @@ -1,8 +1,14 @@ -#include "ftxui/component/button.hpp" +#include // for function +#include // for unique_ptr, make_u... +#include // for wstring +#include // for move +#include // for vector -#include "ftxui/component/component.hpp" -#include "ftxui/component/container.hpp" -#include "ftxui/component/screen_interactive.hpp" +#include "ftxui/component/button.hpp" // for Button +#include "ftxui/component/component.hpp" // for Component +#include "ftxui/component/container.hpp" // for Container +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include "ftxui/screen/box.hpp" // for ftxui using namespace ftxui; diff --git a/examples/component/checkbox.cpp b/examples/component/checkbox.cpp index a0cb0b86..47189b64 100644 --- a/examples/component/checkbox.cpp +++ b/examples/component/checkbox.cpp @@ -1,8 +1,7 @@ #include "ftxui/component/checkbox.hpp" - -#include "ftxui/component/component.hpp" -#include "ftxui/component/container.hpp" -#include "ftxui/component/screen_interactive.hpp" +#include "ftxui/component/component.hpp" // for Component +#include "ftxui/component/container.hpp" // for Container +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive using namespace ftxui; diff --git a/examples/component/checkbox_in_frame.cpp b/examples/component/checkbox_in_frame.cpp index 608f2d2f..c1f0f961 100644 --- a/examples/component/checkbox_in_frame.cpp +++ b/examples/component/checkbox_in_frame.cpp @@ -1,10 +1,15 @@ -#include "ftxui/component/checkbox.hpp" -#include "ftxui/component/container.hpp" -#include "ftxui/component/input.hpp" -#include "ftxui/component/menu.hpp" -#include "ftxui/component/screen_interactive.hpp" -#include "ftxui/component/toggle.hpp" -#include "ftxui/screen/string.hpp" +#include // for allocator_traits<>... +#include // for operator+, wstring +#include // for move +#include // for vector + +#include "ftxui/component/checkbox.hpp" // for CheckBox +#include "ftxui/component/component.hpp" // for Component +#include "ftxui/component/container.hpp" // for Container +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include "ftxui/dom/elements.hpp" // for Element, operator| +#include "ftxui/screen/box.hpp" // for ftxui +#include "ftxui/screen/string.hpp" // for to_wstring using namespace ftxui; diff --git a/examples/component/gallery.cpp b/examples/component/gallery.cpp index 9bd5c868..d819c54c 100644 --- a/examples/component/gallery.cpp +++ b/examples/component/gallery.cpp @@ -1,12 +1,20 @@ -#include "ftxui/component/button.hpp" -#include "ftxui/component/checkbox.hpp" -#include "ftxui/component/container.hpp" -#include "ftxui/component/input.hpp" -#include "ftxui/component/menu.hpp" -#include "ftxui/component/radiobox.hpp" -#include "ftxui/component/screen_interactive.hpp" -#include "ftxui/component/slider.hpp" -#include "ftxui/component/toggle.hpp" +#include // for function +#include // for allocator, unique_ptr +#include // for wstring +#include // for vector + +#include "ftxui/component/button.hpp" // for Button +#include "ftxui/component/checkbox.hpp" // for CheckBox +#include "ftxui/component/component.hpp" // for Component, Compone... +#include "ftxui/component/container.hpp" // for Container +#include "ftxui/component/input.hpp" // for Input +#include "ftxui/component/menu.hpp" // for Menu +#include "ftxui/component/radiobox.hpp" // for RadioBox +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include "ftxui/component/slider.hpp" // for Slider +#include "ftxui/component/toggle.hpp" // for Toggle +#include "ftxui/dom/elements.hpp" // for separator, operator| +#include "ftxui/screen/box.hpp" // for ftxui using namespace ftxui; @@ -73,10 +81,11 @@ class MyComponent : public Component { Element Render(std::wstring name, Element element) { return hbox({ - text(name) | size(WIDTH, EQUAL, 8), - separator(), - element | xflex, - }) | xflex; + text(name) | size(WIDTH, EQUAL, 8), + separator(), + element | xflex, + }) | + xflex; } Element Render(std::wstring name, Component& component) { diff --git a/examples/component/homescreen.cpp b/examples/component/homescreen.cpp index ac8fc83b..b6c49c79 100644 --- a/examples/component/homescreen.cpp +++ b/examples/component/homescreen.cpp @@ -1,14 +1,23 @@ -#include -#include +#include // for operator""s, chron... +#include // for sin +#include // for ref, reference_wra... +#include // for allocator, wstring +#include // for sleep_for, thread +#include // for move +#include // for vector -#include "ftxui/component/checkbox.hpp" -#include "ftxui/component/container.hpp" -#include "ftxui/component/input.hpp" -#include "ftxui/component/menu.hpp" -#include "ftxui/component/radiobox.hpp" -#include "ftxui/component/screen_interactive.hpp" -#include "ftxui/component/toggle.hpp" -#include "ftxui/screen/string.hpp" +#include "ftxui/component/checkbox.hpp" // for CheckBox +#include "ftxui/component/component.hpp" // for Component +#include "ftxui/component/container.hpp" // for Container +#include "ftxui/component/event.hpp" // for Event, Event::Custom +#include "ftxui/component/input.hpp" // for Input +#include "ftxui/component/menu.hpp" // for Menu +#include "ftxui/component/radiobox.hpp" // for RadioBox +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include "ftxui/component/toggle.hpp" // for Toggle +#include "ftxui/dom/elements.hpp" // for text, operator| +#include "ftxui/screen/box.hpp" // for ftxui +#include "ftxui/screen/color.hpp" // for Color, Color::Blue... using namespace ftxui; diff --git a/examples/component/input.cpp b/examples/component/input.cpp index 2f2eb51e..3fc69e18 100644 --- a/examples/component/input.cpp +++ b/examples/component/input.cpp @@ -1,10 +1,6 @@ #include "ftxui/component/input.hpp" - -#include - -#include "ftxui/component/container.hpp" -#include "ftxui/component/screen_interactive.hpp" -#include "ftxui/screen/string.hpp" +#include "ftxui/component/container.hpp" // for Container +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive using namespace ftxui; diff --git a/examples/component/menu.cpp b/examples/component/menu.cpp index 1fd33e3e..41860fe4 100644 --- a/examples/component/menu.cpp +++ b/examples/component/menu.cpp @@ -1,10 +1,11 @@ -#include "ftxui/component/menu.hpp" +#include // for function +#include // for basic_ostream::ope... +#include // for wstring, allocator +#include // for vector -#include -#include -#include - -#include "ftxui/component/screen_interactive.hpp" +#include "ftxui/component/menu.hpp" // for Menu +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include "ftxui/screen/box.hpp" // for ftxui int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/component/menu2.cpp b/examples/component/menu2.cpp index dd422f6f..91aacf8e 100644 --- a/examples/component/menu2.cpp +++ b/examples/component/menu2.cpp @@ -1,11 +1,14 @@ -#include -#include -#include +#include // for function +#include // for wstring, allocator +#include // for vector -#include "ftxui/component/container.hpp" -#include "ftxui/component/menu.hpp" -#include "ftxui/component/screen_interactive.hpp" -#include "ftxui/screen/string.hpp" +#include "ftxui/component/component.hpp" // for Component +#include "ftxui/component/container.hpp" // for Container +#include "ftxui/component/menu.hpp" // for Menu +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include "ftxui/dom/elements.hpp" // for text, separator, bold +#include "ftxui/screen/box.hpp" // for ftxui +#include "ftxui/screen/string.hpp" // for to_wstring using namespace ftxui; diff --git a/examples/component/menu_style.cpp b/examples/component/menu_style.cpp index da1fb684..3fc8879c 100644 --- a/examples/component/menu_style.cpp +++ b/examples/component/menu_style.cpp @@ -1,10 +1,15 @@ -#include -#include +#include // for function +#include // for initializer_list +#include // for wstring, allocator +#include // for vector -#include "ftxui/component/container.hpp" -#include "ftxui/component/menu.hpp" -#include "ftxui/component/screen_interactive.hpp" -#include "ftxui/screen/string.hpp" +#include "ftxui/component/component.hpp" // for Component +#include "ftxui/component/container.hpp" // for Container +#include "ftxui/component/menu.hpp" // for Menu +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include "ftxui/dom/elements.hpp" // for operator|, Element +#include "ftxui/screen/box.hpp" // for ftxui +#include "ftxui/screen/color.hpp" // for Color, Color::Blue using namespace ftxui; @@ -13,7 +18,14 @@ class MyComponent : public Component { MyComponent() { Add(&container); - for (Menu* menu : {&menu_1, &menu_2, &menu_3, &menu_4, &menu_5, &menu_6,}) { + for (Menu* menu : { + &menu_1, + &menu_2, + &menu_3, + &menu_4, + &menu_5, + &menu_6, + }) { container.Add(menu); menu->entries = { L"Monkey", L"Dog", L"Cat", L"Bird", L"Elephant", diff --git a/examples/component/modal_dialog.cpp b/examples/component/modal_dialog.cpp index 520fd78f..d325e491 100644 --- a/examples/component/modal_dialog.cpp +++ b/examples/component/modal_dialog.cpp @@ -1,7 +1,14 @@ -#include "ftxui/component/button.hpp" -#include "ftxui/component/component.hpp" -#include "ftxui/component/container.hpp" -#include "ftxui/component/screen_interactive.hpp" +#include // for function +#include // for allocator_traits<>... +#include // for operator+, wstring +#include // for vector + +#include "ftxui/component/button.hpp" // for Button +#include "ftxui/component/component.hpp" // for Component +#include "ftxui/component/container.hpp" // for Container +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include "ftxui/dom/elements.hpp" // for Element, operator| +#include "ftxui/screen/box.hpp" // for ftxui using namespace ftxui; diff --git a/examples/component/radiobox.cpp b/examples/component/radiobox.cpp index 62d0f1ef..0a3a6507 100644 --- a/examples/component/radiobox.cpp +++ b/examples/component/radiobox.cpp @@ -1,8 +1,5 @@ #include "ftxui/component/radiobox.hpp" - -#include "ftxui/component/component.hpp" -#include "ftxui/component/container.hpp" -#include "ftxui/component/screen_interactive.hpp" +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive using namespace ftxui; diff --git a/examples/component/radiobox_in_frame.cpp b/examples/component/radiobox_in_frame.cpp index 0137425f..09c86445 100644 --- a/examples/component/radiobox_in_frame.cpp +++ b/examples/component/radiobox_in_frame.cpp @@ -1,11 +1,12 @@ -#include "ftxui/component/checkbox.hpp" -#include "ftxui/component/container.hpp" -#include "ftxui/component/input.hpp" -#include "ftxui/component/menu.hpp" -#include "ftxui/component/radiobox.hpp" -#include "ftxui/component/screen_interactive.hpp" -#include "ftxui/component/toggle.hpp" -#include "ftxui/screen/string.hpp" +#include // for wstring, operator+ +#include // for vector + +#include "ftxui/component/component.hpp" // for Component +#include "ftxui/component/radiobox.hpp" // for RadioBox +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include "ftxui/dom/elements.hpp" // for Element, operator| +#include "ftxui/screen/box.hpp" // for ftxui +#include "ftxui/screen/string.hpp" // for to_wstring using namespace ftxui; diff --git a/examples/component/slider.cpp b/examples/component/slider.cpp index 65cb068d..9e7b6f13 100644 --- a/examples/component/slider.cpp +++ b/examples/component/slider.cpp @@ -1,16 +1,21 @@ -#include "ftxui/component/slider.hpp" -#include "ftxui/component/container.hpp" -#include "ftxui/component/screen_interactive.hpp" -#include "ftxui/component/toggle.hpp" -#include "ftxui/screen/string.hpp" +#include // for function +#include // for allocator, unique_ptr +#include // for operator+, to_wstring + +#include "ftxui/component/component.hpp" // for Component, Compone... +#include "ftxui/component/container.hpp" // for Container +#include "ftxui/component/event.hpp" // for Event, Event::Escape +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include "ftxui/component/slider.hpp" // for Slider +#include "ftxui/dom/elements.hpp" // for separator, operator| +#include "ftxui/screen/box.hpp" // for ftxui +#include "ftxui/screen/color.hpp" // for Color using namespace ftxui; Element ColorTile(int red, int green, int blue) { - return text(L"") - | size(WIDTH, GREATER_THAN, 14) - | size(HEIGHT, GREATER_THAN, 7) - | bgcolor(Color::RGB(red, green, blue)); + return text(L"") | size(WIDTH, GREATER_THAN, 14) | + size(HEIGHT, GREATER_THAN, 7) | bgcolor(Color::RGB(red, green, blue)); } Element ColorString(int red, int green, int blue) { diff --git a/examples/component/tab_horizontal.cpp b/examples/component/tab_horizontal.cpp index a475e4bc..8d4b8225 100644 --- a/examples/component/tab_horizontal.cpp +++ b/examples/component/tab_horizontal.cpp @@ -1,11 +1,14 @@ -#include -#include +#include // for function +#include // for wstring, allocator +#include // for vector -#include "ftxui/component/container.hpp" -#include "ftxui/component/radiobox.hpp" -#include "ftxui/component/screen_interactive.hpp" -#include "ftxui/component/toggle.hpp" -#include "ftxui/screen/string.hpp" +#include "ftxui/component/component.hpp" // for Component +#include "ftxui/component/container.hpp" // for Container +#include "ftxui/component/radiobox.hpp" // for RadioBox +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include "ftxui/component/toggle.hpp" // for Toggle +#include "ftxui/dom/elements.hpp" // for Element, operator| +#include "ftxui/screen/box.hpp" // for ftxui using namespace ftxui; diff --git a/examples/component/tab_vertical.cpp b/examples/component/tab_vertical.cpp index b32a8d9b..398be13d 100644 --- a/examples/component/tab_vertical.cpp +++ b/examples/component/tab_vertical.cpp @@ -1,10 +1,12 @@ -#include +#include // for function +#include // for wstring, allocator +#include // for vector -#include "ftxui/component/container.hpp" -#include "ftxui/component/menu.hpp" -#include "ftxui/component/screen_interactive.hpp" -#include "ftxui/component/toggle.hpp" -#include "ftxui/screen/string.hpp" +#include "ftxui/component/component.hpp" // for Component +#include "ftxui/component/container.hpp" // for Container +#include "ftxui/component/menu.hpp" // for Menu +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include "ftxui/screen/box.hpp" // for ftxui using namespace ftxui; diff --git a/examples/component/toggle.cpp b/examples/component/toggle.cpp index ef2cd3ab..5ecf0920 100644 --- a/examples/component/toggle.cpp +++ b/examples/component/toggle.cpp @@ -1,12 +1,7 @@ #include "ftxui/component/toggle.hpp" - -#include -#include -#include - -#include "ftxui/component/container.hpp" -#include "ftxui/component/screen_interactive.hpp" -#include "ftxui/screen/string.hpp" +#include "ftxui/component/container.hpp" // for Container +#include "ftxui/component/event.hpp" // for Event, Event::Return +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive using namespace ftxui; diff --git a/examples/dom/border.cpp b/examples/dom/border.cpp index 57fa7b3a..bd127012 100644 --- a/examples/dom/border.cpp +++ b/examples/dom/border.cpp @@ -1,8 +1,9 @@ -#include #include #include -#include -#include +#include + +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/color_gallery.cpp b/examples/dom/color_gallery.cpp index 0775ad15..8bdd3e73 100644 --- a/examples/dom/color_gallery.cpp +++ b/examples/dom/color_gallery.cpp @@ -1,14 +1,16 @@ -#include #include #include #include #include -#include - -#include "ftxui/screen/string.hpp" +#include +#include +#include using namespace ftxui; #include "./color_info_sorted_2d.ipp" // ColorInfoSorted2D. +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/color.hpp" int main(int argc, const char* argv[]) { // clang-format off diff --git a/examples/dom/color_info_palette256.cpp b/examples/dom/color_info_palette256.cpp index 68a1d180..0e172f47 100644 --- a/examples/dom/color_info_palette256.cpp +++ b/examples/dom/color_info_palette256.cpp @@ -1,10 +1,13 @@ -#include -#include #include #include #include -#include -#include +#include +#include +#include + +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/color.hpp" #include "ftxui/screen/string.hpp" using namespace ftxui; diff --git a/examples/dom/color_truecolor_HSV.cpp b/examples/dom/color_truecolor_HSV.cpp index ad902bb0..0aa63171 100644 --- a/examples/dom/color_truecolor_HSV.cpp +++ b/examples/dom/color_truecolor_HSV.cpp @@ -1,10 +1,11 @@ -#include #include #include -#include -#include +#include +#include -#include "ftxui/screen/string.hpp" +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/color.hpp" int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/color_truecolor_RGB.cpp b/examples/dom/color_truecolor_RGB.cpp index d35788e0..1fd632ae 100644 --- a/examples/dom/color_truecolor_RGB.cpp +++ b/examples/dom/color_truecolor_RGB.cpp @@ -1,10 +1,11 @@ -#include #include #include -#include -#include +#include +#include -#include "ftxui/screen/string.hpp" +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/color.hpp" int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/dbox.cpp b/examples/dom/dbox.cpp index 2fc712c6..851e3ce4 100644 --- a/examples/dom/dbox.cpp +++ b/examples/dom/dbox.cpp @@ -1,6 +1,9 @@ #include #include -#include +#include + +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/gauge.cpp b/examples/dom/gauge.cpp index eb2a96dd..ae882e83 100644 --- a/examples/dom/gauge.cpp +++ b/examples/dom/gauge.cpp @@ -2,8 +2,12 @@ #include #include #include +#include #include +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" + int main(int argc, const char* argv[]) { using namespace ftxui; using namespace std::chrono_literals; diff --git a/examples/dom/graph.cpp b/examples/dom/graph.cpp index 78c8f468..55d62572 100644 --- a/examples/dom/graph.cpp +++ b/examples/dom/graph.cpp @@ -2,9 +2,15 @@ #include #include #include -#include +#include #include +#include #include +#include + +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/color.hpp" class Graph { public: diff --git a/examples/dom/hflow.cpp b/examples/dom/hflow.cpp index aa140a63..6d2cb9db 100644 --- a/examples/dom/hflow.cpp +++ b/examples/dom/hflow.cpp @@ -1,7 +1,11 @@ +#include #include #include #include -#include +#include + +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/html_like.cpp b/examples/dom/html_like.cpp index be565e8e..4f602878 100644 --- a/examples/dom/html_like.cpp +++ b/examples/dom/html_like.cpp @@ -1,10 +1,14 @@ #include #include #include -#include #include +#include #include +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/color.hpp" + int main(int argc, const char* argv[]) { using namespace ftxui; using namespace std::chrono_literals; diff --git a/examples/dom/package_manager.cpp b/examples/dom/package_manager.cpp index 11cbd5f5..1ae23b33 100644 --- a/examples/dom/package_manager.cpp +++ b/examples/dom/package_manager.cpp @@ -4,9 +4,16 @@ #include #include #include +#include +#include #include +#include #include +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/color.hpp" + /// @example examples/dom/package_manage.cpp int main(int argc, const char* argv[]) { diff --git a/examples/dom/paragraph.cpp b/examples/dom/paragraph.cpp index adb1f38f..9a1a614a 100644 --- a/examples/dom/paragraph.cpp +++ b/examples/dom/paragraph.cpp @@ -1,7 +1,10 @@ +#include #include #include -#include -#include +#include + +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/separator.cpp b/examples/dom/separator.cpp index f3bf1a31..0f258a34 100644 --- a/examples/dom/separator.cpp +++ b/examples/dom/separator.cpp @@ -1,6 +1,9 @@ #include #include -#include +#include + +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/size.cpp b/examples/dom/size.cpp index dfeea1d8..bc736d42 100644 --- a/examples/dom/size.cpp +++ b/examples/dom/size.cpp @@ -1,7 +1,12 @@ #include #include #include -#include +#include +#include +#include + +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/spinner.cpp b/examples/dom/spinner.cpp index 7fff889e..e5c3a262 100644 --- a/examples/dom/spinner.cpp +++ b/examples/dom/spinner.cpp @@ -3,7 +3,13 @@ #include #include #include +#include #include +#include +#include + +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/style_blink.cpp b/examples/dom/style_blink.cpp index 114a0d4a..64645bf6 100644 --- a/examples/dom/style_blink.cpp +++ b/examples/dom/style_blink.cpp @@ -1,6 +1,9 @@ #include #include -#include +#include + +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/style_bold.cpp b/examples/dom/style_bold.cpp index e395d784..df0dd6e3 100644 --- a/examples/dom/style_bold.cpp +++ b/examples/dom/style_bold.cpp @@ -1,6 +1,9 @@ #include #include -#include +#include + +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/style_color.cpp b/examples/dom/style_color.cpp index f50fddb3..f96e3ccf 100644 --- a/examples/dom/style_color.cpp +++ b/examples/dom/style_color.cpp @@ -1,6 +1,10 @@ #include #include -#include +#include + +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/color.hpp" int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/style_dim.cpp b/examples/dom/style_dim.cpp index 1c4d4469..61b73d70 100644 --- a/examples/dom/style_dim.cpp +++ b/examples/dom/style_dim.cpp @@ -1,6 +1,9 @@ #include #include -#include +#include + +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/style_gallery.cpp b/examples/dom/style_gallery.cpp index 0ce864f4..4439aa63 100644 --- a/examples/dom/style_gallery.cpp +++ b/examples/dom/style_gallery.cpp @@ -1,6 +1,10 @@ #include #include -#include +#include + +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/color.hpp" int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/style_inverted.cpp b/examples/dom/style_inverted.cpp index 9a191810..3712deba 100644 --- a/examples/dom/style_inverted.cpp +++ b/examples/dom/style_inverted.cpp @@ -1,6 +1,9 @@ #include #include -#include +#include + +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/style_underlined.cpp b/examples/dom/style_underlined.cpp index dedf04ab..52a8d7ad 100644 --- a/examples/dom/style_underlined.cpp +++ b/examples/dom/style_underlined.cpp @@ -1,6 +1,9 @@ #include #include -#include +#include + +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/vbox_hbox.cpp b/examples/dom/vbox_hbox.cpp index 92d23cdf..65b55a85 100644 --- a/examples/dom/vbox_hbox.cpp +++ b/examples/dom/vbox_hbox.cpp @@ -1,6 +1,10 @@ +#include #include #include -#include +#include + +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/window.cpp b/examples/dom/window.cpp index df845617..ea2e9172 100644 --- a/examples/dom/window.cpp +++ b/examples/dom/window.cpp @@ -1,6 +1,10 @@ #include #include -#include +#include + +#include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/color.hpp" int main(void) { using namespace ftxui; diff --git a/examples/util/print_key_press.cpp b/examples/util/print_key_press.cpp index 3ba98485..3f255b58 100644 --- a/examples/util/print_key_press.cpp +++ b/examples/util/print_key_press.cpp @@ -2,12 +2,18 @@ // Use of this source code is governed by the MIT license that can be found in // the LICENSE file. -#include -#include -#include -#include -#include -#include +#include // for size_t +#include // for max +#include // for Component +#include // for ScreenInteractive +#include // for allocator, operator+ +#include // for move +#include // for vector + +#include "ftxui/component/event.hpp" // for Event +#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left +#include "ftxui/dom/elements.hpp" // for text, vbox, window +#include "ftxui/screen/box.hpp" // for ftxui using namespace ftxui; @@ -57,8 +63,8 @@ std::wstring Stringify(Event event) { out += L"_meta"; out += L"(" + // - std::to_wstring(event.mouse().x) + L"," + - std::to_wstring(event.mouse().y) + L")"; + std::to_wstring(event.mouse().x) + L"," + + std::to_wstring(event.mouse().y) + L")"; } else { out += L"(special)"; } diff --git a/include/ftxui/component/button.hpp b/include/ftxui/component/button.hpp index 76e4186a..e7b190c9 100644 --- a/include/ftxui/component/button.hpp +++ b/include/ftxui/component/button.hpp @@ -2,10 +2,14 @@ #define FTXUI_COMPONENT_BUTTON_HPP #include +#include #include "ftxui/component/component.hpp" +#include "ftxui/dom/elements.hpp" +#include "ftxui/screen/box.hpp" namespace ftxui { +struct Event; /// @brief A button. An action is associated to the click event. /// @ingroup dom @@ -25,6 +29,7 @@ class Button : public Component { // Component implementation. Element Render() override; bool OnEvent(Event) override; + private: Box box_; }; diff --git a/include/ftxui/component/captured_mouse.hpp b/include/ftxui/component/captured_mouse.hpp index b76ac10f..9c69a3af 100644 --- a/include/ftxui/component/captured_mouse.hpp +++ b/include/ftxui/component/captured_mouse.hpp @@ -12,3 +12,7 @@ using CapturedMouse = std::unique_ptr; } // namespace ftxui #endif /* end of include guard: FTXUI_CAPTURED_MOUSE_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/component/checkbox.hpp b/include/ftxui/component/checkbox.hpp index f21121b7..214ce524 100644 --- a/include/ftxui/component/checkbox.hpp +++ b/include/ftxui/component/checkbox.hpp @@ -1,11 +1,13 @@ #ifndef FTXUI_COMPONENT_CHECKBOX_HPP #define FTXUI_COMPONENT_CHECKBOX_HPP -#include +#include #include "ftxui/component/component.hpp" +#include "ftxui/screen/box.hpp" namespace ftxui { +struct Event; /// @brief A Checkbox. It can be checked or unchecked.Display an element on a /// ftxui::Screen. @@ -42,7 +44,6 @@ class CheckBox : public Component { int cursor_position = 0; Box box_; - }; } // namespace ftxui diff --git a/include/ftxui/component/component.hpp b/include/ftxui/component/component.hpp index 5a422163..9003f1c1 100644 --- a/include/ftxui/component/component.hpp +++ b/include/ftxui/component/component.hpp @@ -1,14 +1,17 @@ #ifndef FTXUI_COMPONENT_COMPONENT_HPP #define FTXUI_COMPONENT_COMPONENT_HPP -#include -#include "ftxui/component/event.hpp" -#include "ftxui/dom/elements.hpp" +#include // for unique_ptr +#include // for vector + +#include "ftxui/component/captured_mouse.hpp" // for CaptureMouse +#include "ftxui/dom/elements.hpp" // for Element namespace ftxui { class Delegate; class Focus; +struct Event; /// @brief It implement rendering itself as ftxui::Element. It implement /// keyboard navigation by responding to ftxui::Event. @@ -53,6 +56,8 @@ class Component { void TakeFocus(); protected: + CapturedMouse CaptureMouse(const Event& event); + std::vector children_; private: diff --git a/include/ftxui/component/container.hpp b/include/ftxui/component/container.hpp index 03cee397..3f78798f 100644 --- a/include/ftxui/component/container.hpp +++ b/include/ftxui/component/container.hpp @@ -2,6 +2,8 @@ #define FTXUI_COMPONENT_CONTAINER_HPP #include "ftxui/component/component.hpp" +#include "ftxui/component/event.hpp" +#include "ftxui/dom/elements.hpp" namespace ftxui { diff --git a/include/ftxui/component/event.hpp b/include/ftxui/component/event.hpp index 6295c919..7da613ee 100644 --- a/include/ftxui/component/event.hpp +++ b/include/ftxui/component/event.hpp @@ -1,16 +1,14 @@ #ifndef FTXUI_COMPONENT_EVENT_HPP #define FTXUI_COMPONENT_EVENT_HPP -#include -#include -#include -#include -#include +#include // for Mouse +#include // for string, operator== #include namespace ftxui { class ScreenInteractive; +class Component; /// @brief Represent an event. It can be key press event, a terminal resize, or /// more ... @@ -53,7 +51,7 @@ struct Event { static Event Custom; //--- Method section --------------------------------------------------------- - bool is_character() const { return type_ == Type::Character;} + bool is_character() const { return type_ == Type::Character; } wchar_t character() const { return character_; } bool is_mouse() const { return type_ == Type::Mouse; } @@ -67,13 +65,12 @@ struct Event { const std::string& input() const { return input_; } - ScreenInteractive* screen() { return screen_; } - void SetScreen(ScreenInteractive* screen) { screen_ = screen; } - bool operator==(const Event& other) const { return input_ == other.input_; } //--- State section ---------------------------------------------------------- private: + friend Component; + friend ScreenInteractive; enum class Type { Unknown, Character, @@ -94,10 +91,9 @@ struct Event { }; std::string input_; - ScreenInteractive* screen_; + ScreenInteractive* screen_ = nullptr; }; - } // namespace ftxui #endif /* end of include guard: FTXUI_COMPONENT_EVENT_HPP */ diff --git a/include/ftxui/component/input.hpp b/include/ftxui/component/input.hpp index a55bd307..fedeacbf 100644 --- a/include/ftxui/component/input.hpp +++ b/include/ftxui/component/input.hpp @@ -2,10 +2,14 @@ #define FTXUI_COMPONENT_INPUT_H_ #include +#include #include "ftxui/component/component.hpp" +#include "ftxui/dom/elements.hpp" +#include "ftxui/screen/box.hpp" namespace ftxui { +struct Event; /// @brief An input box. The user can type text into it. /// @ingroup component. diff --git a/include/ftxui/component/menu.hpp b/include/ftxui/component/menu.hpp index d6213634..8e3f2b16 100644 --- a/include/ftxui/component/menu.hpp +++ b/include/ftxui/component/menu.hpp @@ -2,11 +2,15 @@ #define FTXUI_COMPONENT_MENU #include +#include +#include #include "ftxui/component/component.hpp" #include "ftxui/dom/elements.hpp" +#include "ftxui/screen/box.hpp" namespace ftxui { +struct Event; /// @brief A list of items. The user can navigate through them. /// @ingroup component diff --git a/include/ftxui/component/mouse.hpp b/include/ftxui/component/mouse.hpp index 54e80d4b..aeeb4909 100644 --- a/include/ftxui/component/mouse.hpp +++ b/include/ftxui/component/mouse.hpp @@ -1,3 +1,5 @@ +#ifndef FTXUI_COMPONENT_MOUSE_HPP +#define FTXUI_COMPONENT_MOUSE_HPP namespace ftxui { /// @brief A mouse event. It contains the coordinate of the mouse, the button @@ -39,3 +41,4 @@ struct Mouse { // 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. +#endif /* end of include guard: FTXUI_COMPONENT_MOUSE_HPP */ diff --git a/include/ftxui/component/radiobox.hpp b/include/ftxui/component/radiobox.hpp index bbfc6f72..74932450 100644 --- a/include/ftxui/component/radiobox.hpp +++ b/include/ftxui/component/radiobox.hpp @@ -1,11 +1,15 @@ #ifndef FTXUI_COMPONENT_RADIOBOX_HPP #define FTXUI_COMPONENT_RADIOBOX_HPP -#include +#include +#include #include "ftxui/component/component.hpp" +#include "ftxui/dom/elements.hpp" +#include "ftxui/screen/box.hpp" namespace ftxui { +struct Event; /// @brief A list of selectable element. One and only one can be selected at /// the same time. diff --git a/include/ftxui/component/receiver.hpp b/include/ftxui/component/receiver.hpp index 7b859224..8b236c35 100644 --- a/include/ftxui/component/receiver.hpp +++ b/include/ftxui/component/receiver.hpp @@ -1,13 +1,13 @@ #ifndef FTXUI_COMPONENT_RECEIVER_HPP_ #define FTXUI_COMPONENT_RECEIVER_HPP_ -#include -#include +#include // for atomic +#include // for condition_variable #include #include -#include -#include -#include +#include // for unique_ptr, make_unique +#include // for mutex, unique_lock +#include // for queue namespace ftxui { @@ -38,6 +38,7 @@ namespace ftxui { // clang-format off template class SenderImpl; template class ReceiverImpl; + template using Sender = std::unique_ptr>; template using Receiver = std::unique_ptr>; template Receiver MakeReceiver(); diff --git a/include/ftxui/component/screen_interactive.hpp b/include/ftxui/component/screen_interactive.hpp index c61132c0..c3a32519 100644 --- a/include/ftxui/component/screen_interactive.hpp +++ b/include/ftxui/component/screen_interactive.hpp @@ -1,20 +1,18 @@ #ifndef FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP #define FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP -#include -#include +#include // for atomic #include -#include -#include -#include -#include +#include // for unique_ptr +#include // for string -#include "ftxui/component/captured_mouse.hpp" +#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse #include "ftxui/component/event.hpp" -#include "ftxui/screen/screen.hpp" +#include "ftxui/screen/screen.hpp" // for Screen namespace ftxui { class Component; +struct Event; class ScreenInteractive : public Screen { public: diff --git a/include/ftxui/component/slider.hpp b/include/ftxui/component/slider.hpp index f9bff719..6b30d427 100644 --- a/include/ftxui/component/slider.hpp +++ b/include/ftxui/component/slider.hpp @@ -11,13 +11,8 @@ namespace ftxui { // float max = 100.f, // float increment = (max - min) * 0.05f); -template // T = {int, float} -ComponentPtr Slider(std::wstring label, - T* value, - T min, - T max, - T increment); - +template // T = {int, float} +ComponentPtr Slider(std::wstring label, T* value, T min, T max, T increment); } // namespace ftxui diff --git a/include/ftxui/component/toggle.hpp b/include/ftxui/component/toggle.hpp index 8e9a3f65..bbdd1f1d 100644 --- a/include/ftxui/component/toggle.hpp +++ b/include/ftxui/component/toggle.hpp @@ -1,12 +1,15 @@ #ifndef FTXUI_COMPONENT_TOGGLE_H_ #define FTXUI_COMPONENT_TOGGLE_H_ -#include #include +#include #include "ftxui/component/component.hpp" +#include "ftxui/dom/elements.hpp" +#include "ftxui/screen/box.hpp" namespace ftxui { +struct Event; /// @brief An horizontal list of elements. The user can navigate through them. /// @ingroup component diff --git a/include/ftxui/dom/elements.hpp b/include/ftxui/dom/elements.hpp index 614b1c11..073b7833 100644 --- a/include/ftxui/dom/elements.hpp +++ b/include/ftxui/dom/elements.hpp @@ -78,7 +78,7 @@ enum Direction { WIDTH, HEIGHT }; enum Constraint { LESS_THAN, EQUAL, GREATER_THAN }; Decorator size(Direction, Constraint, int value); -// -- +// -- Decorator reflect(Box& box); // --- Frame --- diff --git a/include/ftxui/dom/node.hpp b/include/ftxui/dom/node.hpp index 7998da6b..3ca51394 100644 --- a/include/ftxui/dom/node.hpp +++ b/include/ftxui/dom/node.hpp @@ -1,16 +1,18 @@ #ifndef FTXUI_DOM_NODE_HPP #define FTXUI_DOM_NODE_HPP -#include -#include +#include // for shared_ptr +#include // for vector -#include "ftxui/dom/requirement.hpp" -#include "ftxui/screen/box.hpp" +#include "ftxui/dom/requirement.hpp" // for Requirement +#include "ftxui/screen/box.hpp" // for Box #include "ftxui/screen/screen.hpp" namespace ftxui { class Node; +class Screen; + using Element = std::shared_ptr; using Elements = std::vector>; diff --git a/include/ftxui/dom/take_any_args.hpp b/include/ftxui/dom/take_any_args.hpp index fecee238..3adf2237 100644 --- a/include/ftxui/dom/take_any_args.hpp +++ b/include/ftxui/dom/take_any_args.hpp @@ -1,3 +1,4 @@ +// IWYU pragma: private, include "ftxui/dom/elements.hpp" #include template diff --git a/include/ftxui/screen/color.hpp b/include/ftxui/screen/color.hpp index 6bb0c19b..e8edbcb8 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 -#include -#include +#include // for uint8_t +#include // for wstring #ifdef RGB // Workaround for wingdi.h (via Windows.h) defining macros that break things. diff --git a/include/ftxui/screen/color_info.hpp b/include/ftxui/screen/color_info.hpp index b3c64ca4..5a35fc5b 100644 --- a/include/ftxui/screen/color_info.hpp +++ b/include/ftxui/screen/color_info.hpp @@ -1,6 +1,7 @@ #ifndef FTXUI_SCREEN_COLOR_INFO_HPP #define FTXUI_SCREEN_COLOR_INFO_HPP +#include #include namespace ftxui { diff --git a/iwyu.imp b/iwyu.imp new file mode 100644 index 00000000..feaf961b --- /dev/null +++ b/iwyu.imp @@ -0,0 +1,8 @@ +[ + { symbol: [ "VMIN", private, "", public ] }, + { symbol: [ "VTIME", private, "", public ] }, + { symbol: [ "ECHO", private, "", public ] }, + { symbol: [ "ICANON", private, "", public ] }, + { symbol: [ "termios", private, "", public ] }, + { symbol: [ "TCSANOW", private, "", public ] }, +] diff --git a/src/ftxui/component/button.cpp b/src/ftxui/component/button.cpp index 3ea1b777..357b5945 100644 --- a/src/ftxui/component/button.cpp +++ b/src/ftxui/component/button.cpp @@ -1,7 +1,11 @@ -#include "ftxui/component/button.hpp" -#include "ftxui/component/screen_interactive.hpp" +#include // for function +#include // for shared_ptr -#include +#include "ftxui/component/button.hpp" +#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse +#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 ScreenInteractive namespace ftxui { @@ -12,7 +16,7 @@ Element Button::Render() { bool Button::OnEvent(Event event) { if (event.is_mouse() && box_.Contain(event.mouse().x, event.mouse().y)) { - if (!event.screen()->CaptureMouse()) + if (!CaptureMouse(event)) return false; TakeFocus(); diff --git a/src/ftxui/component/checkbox.cpp b/src/ftxui/component/checkbox.cpp index 8c04a085..a7382d87 100644 --- a/src/ftxui/component/checkbox.cpp +++ b/src/ftxui/component/checkbox.cpp @@ -1,7 +1,11 @@ -#include "ftxui/component/checkbox.hpp" -#include "ftxui/component/screen_interactive.hpp" +#include // for function +#include // for shared_ptr -#include +#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse +#include "ftxui/component/checkbox.hpp" +#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 ScreenInteractive namespace ftxui { @@ -27,7 +31,7 @@ bool CheckBox::OnEvent(Event event) { } bool CheckBox::OnMouseEvent(Event event) { - if (!event.screen()->CaptureMouse()) + if (!CaptureMouse(event)) return false; if (!box_.Contain(event.mouse().x, event.mouse().y)) return false; diff --git a/src/ftxui/component/component.cpp b/src/ftxui/component/component.cpp index d89de450..875d759f 100644 --- a/src/ftxui/component/component.cpp +++ b/src/ftxui/component/component.cpp @@ -1,11 +1,20 @@ #include "ftxui/component/component.hpp" -#include - #include +#include "ftxui/component/captured_mouse.hpp" +#include "ftxui/component/event.hpp" +#include "ftxui/component/screen_interactive.hpp" + namespace ftxui { +namespace { +class CaptureMouseImpl : public CapturedMouseInterface { + public: + ~CaptureMouseImpl() override {} +}; +} + Component::~Component() { Detach(); } @@ -97,6 +106,16 @@ void Component::TakeFocus() { } } +/// @brief Take the CapturedMouse if available. There is only one component of +/// them. It represents a component taking priority over others. +/// @argument event +/// @ingroup component +CapturedMouse Component::CaptureMouse(const Event& event) { + if (!event.screen_) + return std::make_unique(); + return event.screen_->CaptureMouse(); +} + /// @brief Detach this children from its parent. /// @see Attach /// @see Detach diff --git a/src/ftxui/component/container.cpp b/src/ftxui/component/container.cpp index 0fdd438f..7c01a1d0 100644 --- a/src/ftxui/component/container.cpp +++ b/src/ftxui/component/container.cpp @@ -1,6 +1,8 @@ #include "ftxui/component/container.hpp" +#include #include +#include namespace ftxui { diff --git a/src/ftxui/component/container_test.cpp b/src/ftxui/component/container_test.cpp index 86f36aec..da47638c 100644 --- a/src/ftxui/component/container_test.cpp +++ b/src/ftxui/component/container_test.cpp @@ -1,6 +1,10 @@ -#include "ftxui/component/container.hpp" +#include // for Message +#include // for TestPartResult, SuiteApiResolver +#include // for allocator -#include "gtest/gtest.h" +#include "ftxui/component/container.hpp" +#include "ftxui/screen/box.hpp" // for ftxui +#include "gtest/gtest_pred_impl.h" // for AssertionResult, EXPECT_EQ, EXPEC... using namespace ftxui; diff --git a/src/ftxui/component/event.cpp b/src/ftxui/component/event.cpp index 2fa0cf05..b8bc436c 100644 --- a/src/ftxui/component/event.cpp +++ b/src/ftxui/component/event.cpp @@ -1,6 +1,6 @@ #include "ftxui/component/event.hpp" -#include +#include "ftxui/component/mouse.hpp" #include "ftxui/screen/string.hpp" namespace ftxui { diff --git a/src/ftxui/component/input.cpp b/src/ftxui/component/input.cpp index d39ec1bb..c9a9daaf 100644 --- a/src/ftxui/component/input.cpp +++ b/src/ftxui/component/input.cpp @@ -1,9 +1,11 @@ #include "ftxui/component/input.hpp" -#include "ftxui/component/screen_interactive.hpp" #include +#include -#include "ftxui/screen/string.hpp" +#include "ftxui/component/captured_mouse.hpp" +#include "ftxui/component/mouse.hpp" +#include "ftxui/component/screen_interactive.hpp" namespace ftxui { @@ -103,7 +105,7 @@ bool Input::OnEvent(Event event) { } bool Input::OnMouseEvent(Event event) { - if (!event.screen()->CaptureMouse()) + if (!CaptureMouse(event)) return false; if (!input_box_.Contain(event.mouse().x, event.mouse().y)) return false; diff --git a/src/ftxui/component/menu.cpp b/src/ftxui/component/menu.cpp index 44f5f364..90b19878 100644 --- a/src/ftxui/component/menu.cpp +++ b/src/ftxui/component/menu.cpp @@ -1,8 +1,13 @@ #include "ftxui/component/menu.hpp" -#include "ftxui/component/screen_interactive.hpp" +#include #include -#include +#include +#include + +#include "ftxui/component/captured_mouse.hpp" +#include "ftxui/component/mouse.hpp" +#include "ftxui/component/screen_interactive.hpp" namespace ftxui { @@ -28,7 +33,7 @@ Element Menu::Render() { } bool Menu::OnEvent(Event event) { - if (!event.screen()->CaptureMouse()) + if (!CaptureMouse(event)) return false; if (event.is_mouse()) return OnMouseEvent(event); @@ -63,7 +68,7 @@ bool Menu::OnEvent(Event event) { } bool Menu::OnMouseEvent(Event event) { - if (!event.screen()->CaptureMouse()) + if (!CaptureMouse(event)) return false; for (int i = 0; i < boxes_.size(); ++i) { if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) diff --git a/src/ftxui/component/radiobox.cpp b/src/ftxui/component/radiobox.cpp index 7c50655f..4d6c00a2 100644 --- a/src/ftxui/component/radiobox.cpp +++ b/src/ftxui/component/radiobox.cpp @@ -1,8 +1,14 @@ #include "ftxui/component/radiobox.hpp" -#include "ftxui/component/screen_interactive.hpp" +#include #include #include +#include +#include + +#include "ftxui/component/captured_mouse.hpp" +#include "ftxui/component/mouse.hpp" +#include "ftxui/component/screen_interactive.hpp" namespace ftxui { @@ -13,8 +19,9 @@ Element RadioBox::Render() { for (size_t i = 0; i < entries.size(); ++i) { auto style = (focused == int(i) && is_focused) ? focused_style : unfocused_style; - auto focus_management = - (focused != int(i)) ? nothing : is_focused ? focus : select; + auto focus_management = (focused != int(i)) ? nothing + : is_focused ? focus + : select; const std::wstring& symbol = selected == int(i) ? checked : unchecked; elements.push_back(hbox(text(symbol), text(entries[i]) | style) | @@ -24,7 +31,7 @@ Element RadioBox::Render() { } bool RadioBox::OnEvent(Event event) { - if (!event.screen()->CaptureMouse()) + if (!CaptureMouse(event)) return false; if (event.is_mouse()) return OnMouseEvent(event); @@ -58,7 +65,7 @@ bool RadioBox::OnEvent(Event event) { } bool RadioBox::OnMouseEvent(Event event) { - if (!event.screen()->CaptureMouse()) + if (!CaptureMouse(event)) return false; for (int i = 0; i < boxes_.size(); ++i) { if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) diff --git a/src/ftxui/component/radiobox_test.cpp b/src/ftxui/component/radiobox_test.cpp index 8fd5c2d3..845dac0f 100644 --- a/src/ftxui/component/radiobox_test.cpp +++ b/src/ftxui/component/radiobox_test.cpp @@ -1,6 +1,10 @@ -#include "ftxui/component/radiobox.hpp" +#include // for Message +#include // for TestPartResult, SuiteApiResolver, TestFactoryImpl -#include "gtest/gtest.h" +#include "ftxui/component/event.hpp" // for Event, Event::ArrowDown, Event::ArrowUp, Event::Tab, Event::TabReverse +#include "ftxui/component/mouse.hpp" // for ftxui +#include "ftxui/component/radiobox.hpp" +#include "gtest/gtest_pred_impl.h" // for EXPECT_EQ, Test, TEST using namespace ftxui; diff --git a/src/ftxui/component/receiver_test.cpp b/src/ftxui/component/receiver_test.cpp index 8d06cc8e..bd4e1cb6 100644 --- a/src/ftxui/component/receiver_test.cpp +++ b/src/ftxui/component/receiver_test.cpp @@ -1,8 +1,10 @@ +#include // for Message +#include // for TestPartResult +#include // for thread +#include // for move + #include "ftxui/component/receiver.hpp" - -#include - -#include "gtest/gtest.h" +#include "gtest/gtest_pred_impl.h" // for AssertionResult, Test, EXPECT_EQ using namespace ftxui; diff --git a/src/ftxui/component/screen_interactive.cpp b/src/ftxui/component/screen_interactive.cpp index 95cc26cc..48bd747f 100644 --- a/src/ftxui/component/screen_interactive.cpp +++ b/src/ftxui/component/screen_interactive.cpp @@ -1,19 +1,24 @@ #include "ftxui/component/screen_interactive.hpp" -#include +#include // for fileno, stdin +#include // for copy, max, min +#include // for signal, SIGINT +#include // for exit, NULL +#include // for cout, ostream +#include // for stack +#include // for thread +#include // for move +#include // for vector -#include -#include -#include -#include -#include -#include - -#include "ftxui/component/captured_mouse.hpp" -#include "ftxui/component/component.hpp" -#include "ftxui/component/terminal_input_parser.hpp" -#include "ftxui/screen/string.hpp" -#include "ftxui/screen/terminal.hpp" +#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse +#include "ftxui/component/component.hpp" // for Component +#include "ftxui/component/event.hpp" // for Event +#include "ftxui/component/mouse.hpp" // for Mouse +#include "ftxui/component/receiver.hpp" // for ReceiverImpl +#include "ftxui/component/terminal_input_parser.hpp" // for TerminalInputPa... +#include "ftxui/dom/node.hpp" // for Node, Render +#include "ftxui/dom/requirement.hpp" // for Requirement +#include "ftxui/screen/terminal.hpp" // for Terminal::Dimen... #if defined(_WIN32) #define DEFINE_CONSOLEV2_PROPERTIES @@ -26,8 +31,9 @@ #error Must be compiled in UNICODE mode #endif #else -#include -#include +#include // for select, FD_ISSET +#include // for tcsetattr, tcge... +#include // for STDIN_FILENO, read #endif // Quick exit is missing in standard CLang headers @@ -48,8 +54,7 @@ constexpr int timeout_milliseconds = 20; constexpr int timeout_microseconds = timeout_milliseconds * 1000; #if defined(_WIN32) -void EventListener(std::atomic* quit, - Sender out) { +void EventListener(std::atomic* quit, Sender out) { auto console = GetStdHandle(STD_INPUT_HANDLE); auto parser = TerminalInputParser(out->Clone()); while (!*quit) { @@ -69,8 +74,7 @@ void EventListener(std::atomic* quit, std::vector records{number_of_events}; DWORD number_of_events_read = 0; - ReadConsoleInput(console, records.data(), - (DWORD)records.size(), + ReadConsoleInput(console, records.data(), (DWORD)records.size(), &number_of_events_read); records.resize(number_of_events_read); @@ -106,7 +110,7 @@ void EventListener(std::atomic* quit, Sender out) { char c; while (!*quit) { - while(read(STDIN_FILENO, &c, 1), c) + while (read(STDIN_FILENO, &c, 1), c) parser.Add(c); emscripten_sleep(1); @@ -115,7 +119,7 @@ void EventListener(std::atomic* quit, Sender out) { } #else -#include +#include // for timeval int CheckStdinReady(int usec_timeout) { timeval tv = {0, usec_timeout}; @@ -219,8 +223,7 @@ void OnResize(int /* signal */) { class CapturedMouseImpl : public CapturedMouseInterface { public: - CapturedMouseImpl(std::function callback) - : callback_(callback) {} + CapturedMouseImpl(std::function callback) : callback_(callback) {} ~CapturedMouseImpl() override { callback_(); } private: @@ -366,7 +369,7 @@ void ScreenInteractive::Loop(Component* component) { }); enable({ - //DECMode::kMouseVt200, + // DECMode::kMouseVt200, DECMode::kMouseAnyEvent, DECMode::kMouseUtf8, DECMode::kMouseSgrExtMode, @@ -406,7 +409,7 @@ void ScreenInteractive::Loop(Component* component) { event.mouse().y -= cursor_y_; } - event.SetScreen(this); + event.screen_ = this; component->OnEvent(event); } diff --git a/src/ftxui/component/slider.cpp b/src/ftxui/component/slider.cpp index 8ddb4fb4..122e523b 100644 --- a/src/ftxui/component/slider.cpp +++ b/src/ftxui/component/slider.cpp @@ -1,10 +1,18 @@ #include "ftxui/component/slider.hpp" + +#include +#include + #include "ftxui/component/captured_mouse.hpp" +#include "ftxui/component/mouse.hpp" #include "ftxui/component/screen_interactive.hpp" +#include "ftxui/dom/elements.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/color.hpp" namespace ftxui { -template +template class SliderImpl : public Component { public: SliderImpl(std::wstring label, T* value, T min, T max, T increment) @@ -55,7 +63,7 @@ class SliderImpl : public Component { } if (box_.Contain(event.mouse().x, event.mouse().y) && - event.screen()->CaptureMouse()) { + CaptureMouse(event)) { TakeFocus(); } @@ -63,7 +71,7 @@ class SliderImpl : public Component { event.mouse().motion == Mouse::Pressed && gauge_box_.Contain(event.mouse().x, event.mouse().y) && !captured_mouse_) { - captured_mouse_ = event.screen()->CaptureMouse(); + captured_mouse_ = CaptureMouse(event); } if (captured_mouse_) { @@ -105,3 +113,7 @@ template ComponentPtr Slider(std::wstring label, float increment); } // namespace ftxui + +// 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/src/ftxui/component/terminal_input_parser.cpp b/src/ftxui/component/terminal_input_parser.cpp index b86d5834..acab8e4b 100644 --- a/src/ftxui/component/terminal_input_parser.cpp +++ b/src/ftxui/component/terminal_input_parser.cpp @@ -1,5 +1,8 @@ #include "ftxui/component/terminal_input_parser.hpp" +#include +#include "ftxui/component/event.hpp" + namespace ftxui { TerminalInputParser::TerminalInputParser(Sender out) @@ -61,7 +64,6 @@ void TerminalInputParser::Send(TerminalInputParser::Output output) { return; } // NOT_REACHED(). - } TerminalInputParser::Output TerminalInputParser::Parse() { @@ -227,3 +229,7 @@ TerminalInputParser::Output TerminalInputParser::ParseCursorReporting( } } // namespace ftxui + +// 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/src/ftxui/component/terminal_input_parser.hpp b/src/ftxui/component/terminal_input_parser.hpp index d378694e..69645a6a 100644 --- a/src/ftxui/component/terminal_input_parser.hpp +++ b/src/ftxui/component/terminal_input_parser.hpp @@ -1,10 +1,13 @@ #ifndef FTXUI_COMPONENT_TERMINAL_INPUT_PARSER #define FTXUI_COMPONENT_TERMINAL_INPUT_PARSER -#include "ftxui/component/event.hpp" -#include "ftxui/component/receiver.hpp" +#include // for unique_ptr +#include // for string +#include // for vector -#include +#include "ftxui/component/event.hpp" // IWYU pragma: keep +#include "ftxui/component/mouse.hpp" // for Mouse +#include "ftxui/component/receiver.hpp" // for SenderImpl namespace ftxui { diff --git a/src/ftxui/component/terminal_input_parser_test.cpp b/src/ftxui/component/terminal_input_parser_test.cpp index 6212a1c4..b37b2163 100644 --- a/src/ftxui/component/terminal_input_parser_test.cpp +++ b/src/ftxui/component/terminal_input_parser_test.cpp @@ -1,7 +1,9 @@ -#include "ftxui/component/terminal_input_parser.hpp" -#include "ftxui/component/receiver.hpp" +#include // for Message +#include // for TestPartResult -#include "gtest/gtest.h" +#include "ftxui/component/receiver.hpp" // for MakeReceiver, ReceiverImpl +#include "ftxui/component/terminal_input_parser.hpp" +#include "gtest/gtest_pred_impl.h" // for AssertionResult, Test, Suite... using namespace ftxui; diff --git a/src/ftxui/component/toggle.cpp b/src/ftxui/component/toggle.cpp index 89360966..ca064617 100644 --- a/src/ftxui/component/toggle.cpp +++ b/src/ftxui/component/toggle.cpp @@ -1,7 +1,12 @@ -#include "ftxui/component/toggle.hpp" -#include "ftxui/component/screen_interactive.hpp" +#include // for size_t +#include // for max, min +#include // for shared_ptr, alloca... +#include // for move -#include +#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse +#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include "ftxui/component/toggle.hpp" namespace ftxui { @@ -60,7 +65,7 @@ bool Toggle::OnEvent(Event event) { } bool Toggle::OnMouseEvent(Event event) { - if (!event.screen()->CaptureMouse()) + if (!CaptureMouse(event)) return false; for (int i = 0; i < boxes_.size(); ++i) { if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) diff --git a/src/ftxui/component/toggle_test.cpp b/src/ftxui/component/toggle_test.cpp index acb19ef3..4842d2c0 100644 --- a/src/ftxui/component/toggle_test.cpp +++ b/src/ftxui/component/toggle_test.cpp @@ -1,6 +1,10 @@ -#include "ftxui/component/toggle.hpp" +#include // for Message +#include // for TestPartResult, SuiteApiResolver, TestFactoryImpl -#include "gtest/gtest.h" +#include "ftxui/component/event.hpp" // for Event, Event::ArrowLeft, Event::ArrowRight, Event::Return, Event::Tab, Event::TabReverse +#include "ftxui/component/mouse.hpp" // for ftxui +#include "ftxui/component/toggle.hpp" +#include "gtest/gtest_pred_impl.h" // for AssertionResult, EXPECT_EQ, Test, EXPECT_TRUE, EXPECT_FALSE, TEST using namespace ftxui; diff --git a/src/ftxui/dom/blink.cpp b/src/ftxui/dom/blink.cpp index 8356d836..57a3a230 100644 --- a/src/ftxui/dom/blink.cpp +++ b/src/ftxui/dom/blink.cpp @@ -1,5 +1,10 @@ +#include + #include "ftxui/dom/elements.hpp" +#include "ftxui/dom/node.hpp" #include "ftxui/dom/node_decorator.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/screen.hpp" namespace ftxui { diff --git a/src/ftxui/dom/bold.cpp b/src/ftxui/dom/bold.cpp index f959e814..1d5c3c7b 100644 --- a/src/ftxui/dom/bold.cpp +++ b/src/ftxui/dom/bold.cpp @@ -1,5 +1,10 @@ +#include + #include "ftxui/dom/elements.hpp" +#include "ftxui/dom/node.hpp" #include "ftxui/dom/node_decorator.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/screen.hpp" namespace ftxui { diff --git a/src/ftxui/dom/border.cpp b/src/ftxui/dom/border.cpp index 2d146377..a7ce81c5 100644 --- a/src/ftxui/dom/border.cpp +++ b/src/ftxui/dom/border.cpp @@ -1,7 +1,14 @@ -#include +#include // for max +#include // for begin, end +#include // for make_shared, __shared_ptr_access +#include // for move +#include // for vector -#include "ftxui/dom/elements.hpp" -#include "ftxui/dom/node.hpp" +#include "ftxui/dom/elements.hpp" // for unpack, Element, Decorator, Elements, border, borderWith, window +#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 Pixel, Screen namespace ftxui { diff --git a/src/ftxui/dom/clear_under.cpp b/src/ftxui/dom/clear_under.cpp index da0c6009..23fb36cb 100644 --- a/src/ftxui/dom/clear_under.cpp +++ b/src/ftxui/dom/clear_under.cpp @@ -1,5 +1,10 @@ +#include + #include "ftxui/dom/elements.hpp" +#include "ftxui/dom/node.hpp" #include "ftxui/dom/node_decorator.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/screen.hpp" namespace ftxui { diff --git a/src/ftxui/dom/color.cpp b/src/ftxui/dom/color.cpp index 023dc8f7..475d9786 100644 --- a/src/ftxui/dom/color.cpp +++ b/src/ftxui/dom/color.cpp @@ -1,5 +1,10 @@ +#include + #include "ftxui/dom/elements.hpp" #include "ftxui/dom/node_decorator.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/color.hpp" +#include "ftxui/screen/screen.hpp" namespace ftxui { diff --git a/src/ftxui/dom/composite_decorator.cpp b/src/ftxui/dom/composite_decorator.cpp index c8183276..007057cc 100644 --- a/src/ftxui/dom/composite_decorator.cpp +++ b/src/ftxui/dom/composite_decorator.cpp @@ -1,5 +1,5 @@ + #include "ftxui/dom/elements.hpp" -#include "ftxui/dom/node.hpp" namespace ftxui { diff --git a/src/ftxui/dom/dbox.cpp b/src/ftxui/dom/dbox.cpp index ea737910..e39283bd 100644 --- a/src/ftxui/dom/dbox.cpp +++ b/src/ftxui/dom/dbox.cpp @@ -1,7 +1,12 @@ -#include +#include // for max +#include // for __shared_ptr_access, shared_ptr, make_shared +#include // for move +#include // for vector -#include "ftxui/dom/elements.hpp" -#include "ftxui/dom/node.hpp" +#include "ftxui/dom/elements.hpp" // for Element, Elements, dbox +#include "ftxui/dom/node.hpp" // for Node +#include "ftxui/dom/requirement.hpp" // for Requirement +#include "ftxui/screen/box.hpp" // for Box namespace ftxui { diff --git a/src/ftxui/dom/dim.cpp b/src/ftxui/dom/dim.cpp index 7b6b68ad..296ea1d7 100644 --- a/src/ftxui/dom/dim.cpp +++ b/src/ftxui/dom/dim.cpp @@ -1,5 +1,10 @@ +#include + #include "ftxui/dom/elements.hpp" +#include "ftxui/dom/node.hpp" #include "ftxui/dom/node_decorator.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/screen.hpp" namespace ftxui { diff --git a/src/ftxui/dom/flex.cpp b/src/ftxui/dom/flex.cpp index bf2942e6..303481c4 100644 --- a/src/ftxui/dom/flex.cpp +++ b/src/ftxui/dom/flex.cpp @@ -1,5 +1,10 @@ +#include +#include + #include "ftxui/dom/elements.hpp" #include "ftxui/dom/node.hpp" +#include "ftxui/dom/requirement.hpp" +#include "ftxui/screen/box.hpp" namespace ftxui { diff --git a/src/ftxui/dom/frame.cpp b/src/ftxui/dom/frame.cpp index 7e25c8c0..05f3ea92 100644 --- a/src/ftxui/dom/frame.cpp +++ b/src/ftxui/dom/frame.cpp @@ -1,8 +1,14 @@ -#include +#include // for max, min +#include // for make_shared, shared_ptr, __shared_ptr_access +#include // for move +#include // for vector -#include "ftxui/dom/elements.hpp" -#include "ftxui/dom/node.hpp" -#include "ftxui/util/autoreset.hpp" +#include "ftxui/dom/elements.hpp" // for Element, unpack, focus, frame, select, xframe, yframe +#include "ftxui/dom/node.hpp" // for Node +#include "ftxui/dom/requirement.hpp" // for Requirement, Requirement::FOCUSED, Requirement::SELECTED +#include "ftxui/screen/box.hpp" // for Box +#include "ftxui/screen/screen.hpp" // for Screen, Screen::Cursor +#include "ftxui/util/autoreset.hpp" // for AutoReset namespace ftxui { diff --git a/src/ftxui/dom/gauge.cpp b/src/ftxui/dom/gauge.cpp index d448036a..fe45c4b6 100644 --- a/src/ftxui/dom/gauge.cpp +++ b/src/ftxui/dom/gauge.cpp @@ -1,5 +1,9 @@ +#include + #include "ftxui/dom/elements.hpp" -#include "ftxui/dom/node.hpp" +#include "ftxui/dom/requirement.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/screen.hpp" namespace ftxui { diff --git a/src/ftxui/dom/gauge_test.cpp b/src/ftxui/dom/gauge_test.cpp index 10563967..0eb3275e 100644 --- a/src/ftxui/dom/gauge_test.cpp +++ b/src/ftxui/dom/gauge_test.cpp @@ -1,6 +1,12 @@ -#include "ftxui/dom/elements.hpp" -#include "ftxui/screen/screen.hpp" -#include "gtest/gtest.h" +#include // for Message +#include // for TestPartResult +#include // for allocator + +#include "ftxui/dom/elements.hpp" // for gauge +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui +#include "ftxui/screen/screen.hpp" // for Screen +#include "gtest/gtest_pred_impl.h" // for Test, SuiteApiResolver, EXPECT_EQ using namespace ftxui; using namespace ftxui; diff --git a/src/ftxui/dom/graph.cpp b/src/ftxui/dom/graph.cpp index 67f0cd36..4261bdef 100644 --- a/src/ftxui/dom/graph.cpp +++ b/src/ftxui/dom/graph.cpp @@ -1,4 +1,12 @@ -#include "ftxui/dom/elements.hpp" +#include // for function +#include // for make_shared +#include // for vector + +#include "ftxui/dom/elements.hpp" // for GraphFunction, Element, graph +#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 namespace ftxui { diff --git a/src/ftxui/dom/hbox.cpp b/src/ftxui/dom/hbox.cpp index 3ff91e00..43757e6f 100644 --- a/src/ftxui/dom/hbox.cpp +++ b/src/ftxui/dom/hbox.cpp @@ -1,7 +1,12 @@ -#include +#include // for max +#include // for __shared_ptr_access, shared_ptr, make_shared +#include // for move +#include // for vector -#include "ftxui/dom/elements.hpp" -#include "ftxui/dom/node.hpp" +#include "ftxui/dom/elements.hpp" // for Element, Elements, hbox +#include "ftxui/dom/node.hpp" // for Node +#include "ftxui/dom/requirement.hpp" // for Requirement +#include "ftxui/screen/box.hpp" // for Box namespace ftxui { diff --git a/src/ftxui/dom/hbox_test.cpp b/src/ftxui/dom/hbox_test.cpp index dbeac3a6..fc5ca6c0 100644 --- a/src/ftxui/dom/hbox_test.cpp +++ b/src/ftxui/dom/hbox_test.cpp @@ -1,6 +1,13 @@ -#include "ftxui/dom/elements.hpp" -#include "ftxui/screen/screen.hpp" -#include "gtest/gtest.h" +#include // for Message +#include // for TestPartResult +#include // for allocator, basic_string, string +#include // for vector + +#include "ftxui/dom/elements.hpp" // for text, operator|, Element, flex_grow +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui +#include "ftxui/screen/screen.hpp" // for Screen +#include "gtest/gtest_pred_impl.h" // for Test, SuiteApiResolver, EXPECT_EQ using namespace ftxui; using namespace ftxui; diff --git a/src/ftxui/dom/hflow.cpp b/src/ftxui/dom/hflow.cpp index ee6ff047..eb20233c 100644 --- a/src/ftxui/dom/hflow.cpp +++ b/src/ftxui/dom/hflow.cpp @@ -1,7 +1,12 @@ -#include +#include // for max +#include // for __shared_ptr_access, make_shared, shared_ptr +#include // for move +#include // for vector -#include "ftxui/dom/elements.hpp" -#include "ftxui/dom/node.hpp" +#include "ftxui/dom/elements.hpp" // for Element, Elements, hflow +#include "ftxui/dom/node.hpp" // for Node +#include "ftxui/dom/requirement.hpp" // for Requirement +#include "ftxui/screen/box.hpp" // for Box namespace ftxui { diff --git a/src/ftxui/dom/inverted.cpp b/src/ftxui/dom/inverted.cpp index 10549909..c8595463 100644 --- a/src/ftxui/dom/inverted.cpp +++ b/src/ftxui/dom/inverted.cpp @@ -1,5 +1,10 @@ +#include +#include + #include "ftxui/dom/elements.hpp" #include "ftxui/dom/node_decorator.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/screen.hpp" namespace ftxui { diff --git a/src/ftxui/dom/node.cpp b/src/ftxui/dom/node.cpp index d5f08c7d..9ed078b6 100644 --- a/src/ftxui/dom/node.cpp +++ b/src/ftxui/dom/node.cpp @@ -1,4 +1,7 @@ +#include + #include "ftxui/dom/node.hpp" +#include "ftxui/screen/screen.hpp" namespace ftxui { diff --git a/src/ftxui/dom/node_decorator.cpp b/src/ftxui/dom/node_decorator.cpp index db5c39a5..b98c2c2a 100644 --- a/src/ftxui/dom/node_decorator.cpp +++ b/src/ftxui/dom/node_decorator.cpp @@ -1,4 +1,9 @@ +#include // for __shared_ptr_access +#include // for vector + #include "ftxui/dom/node_decorator.hpp" +#include "ftxui/dom/requirement.hpp" // for Requirement +#include "ftxui/screen/box.hpp" // for Box namespace ftxui { diff --git a/src/ftxui/dom/node_decorator.hpp b/src/ftxui/dom/node_decorator.hpp index 0336b04c..a9f1d4f4 100644 --- a/src/ftxui/dom/node_decorator.hpp +++ b/src/ftxui/dom/node_decorator.hpp @@ -1,9 +1,12 @@ #ifndef FTXUI_DOM_NODE_DECORATOR_H_ #define FTXUI_DOM_NODE_DECORATOR_H_ -#include "ftxui/dom/node.hpp" +#include // for move + +#include "ftxui/dom/node.hpp" // for Node, Elements namespace ftxui { +struct Box; // Helper class. class NodeDecorator : public Node { diff --git a/src/ftxui/dom/paragraph.cpp b/src/ftxui/dom/paragraph.cpp index 7a8a8e7b..a90c18d7 100644 --- a/src/ftxui/dom/paragraph.cpp +++ b/src/ftxui/dom/paragraph.cpp @@ -1,4 +1,5 @@ #include +#include #include "ftxui/dom/elements.hpp" diff --git a/src/ftxui/dom/reflect.cpp b/src/ftxui/dom/reflect.cpp index 0ce40e43..79998ad6 100644 --- a/src/ftxui/dom/reflect.cpp +++ b/src/ftxui/dom/reflect.cpp @@ -1,7 +1,11 @@ #include +#include +#include + #include "ftxui/dom/elements.hpp" #include "ftxui/dom/node.hpp" -#include "ftxui/dom/node_decorator.hpp" +#include "ftxui/dom/requirement.hpp" +#include "ftxui/screen/box.hpp" namespace ftxui { diff --git a/src/ftxui/dom/separator.cpp b/src/ftxui/dom/separator.cpp index 0997d6e4..243249dc 100644 --- a/src/ftxui/dom/separator.cpp +++ b/src/ftxui/dom/separator.cpp @@ -1,5 +1,9 @@ +#include + #include "ftxui/dom/elements.hpp" #include "ftxui/dom/node.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/screen.hpp" namespace ftxui { diff --git a/src/ftxui/dom/size.cpp b/src/ftxui/dom/size.cpp index 5bb4cb41..f5621b68 100644 --- a/src/ftxui/dom/size.cpp +++ b/src/ftxui/dom/size.cpp @@ -1,7 +1,13 @@ -#include +#include // for size_t +#include // for min, max +#include // for make_shared, __shared_ptr_access +#include // for move +#include // for vector -#include "ftxui/dom/elements.hpp" -#include "ftxui/dom/node.hpp" +#include "ftxui/dom/elements.hpp" // for Constraint, Direction, EQUAL, GREATER_THAN, LESS_THAN, WIDTH, unpack, Decorator, Element, size +#include "ftxui/dom/node.hpp" // for Node +#include "ftxui/dom/requirement.hpp" // for Requirement +#include "ftxui/screen/box.hpp" // for Box namespace ftxui { diff --git a/src/ftxui/dom/spinner.cpp b/src/ftxui/dom/spinner.cpp index 24ea38ba..e415acce 100644 --- a/src/ftxui/dom/spinner.cpp +++ b/src/ftxui/dom/spinner.cpp @@ -1,5 +1,9 @@ +#include +#include +#include +#include + #include "ftxui/dom/elements.hpp" -#include "ftxui/dom/node.hpp" namespace ftxui { diff --git a/src/ftxui/dom/text.cpp b/src/ftxui/dom/text.cpp index 0a30f7dd..a8ade9ae 100644 --- a/src/ftxui/dom/text.cpp +++ b/src/ftxui/dom/text.cpp @@ -1,7 +1,13 @@ -#include -#include "ftxui/dom/elements.hpp" -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/string.hpp" +#include // for max +#include // for make_shared +#include // for wstring + +#include "ftxui/dom/elements.hpp" // for Element, text, vtext +#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/string.hpp" // for wchar_width, wstring_width namespace ftxui { diff --git a/src/ftxui/dom/text_test.cpp b/src/ftxui/dom/text_test.cpp index 34fe2a55..a1a55518 100644 --- a/src/ftxui/dom/text_test.cpp +++ b/src/ftxui/dom/text_test.cpp @@ -1,8 +1,12 @@ -#include "ftxui/dom/elements.hpp" -#include "ftxui/screen/screen.hpp" -#include "gtest/gtest.h" +#include // for Message +#include // for TestPartResult +#include // for allocator + +#include "ftxui/dom/elements.hpp" // for text, Element, operator|, border +#include "ftxui/screen/box.hpp" // for ftxui +#include "ftxui/screen/screen.hpp" // for Screen +#include "gtest/gtest_pred_impl.h" // for Test, SuiteApiResolver, EXPECT_EQ -using namespace ftxui; using namespace ftxui; TEST(TextTest, ScreenHeightSmaller) { diff --git a/src/ftxui/dom/underlined.cpp b/src/ftxui/dom/underlined.cpp index b04a1108..7a3a50f1 100644 --- a/src/ftxui/dom/underlined.cpp +++ b/src/ftxui/dom/underlined.cpp @@ -1,5 +1,10 @@ +#include +#include + #include "ftxui/dom/elements.hpp" #include "ftxui/dom/node_decorator.hpp" +#include "ftxui/screen/box.hpp" +#include "ftxui/screen/screen.hpp" namespace ftxui { diff --git a/src/ftxui/dom/util.cpp b/src/ftxui/dom/util.cpp index bc86b1b2..17706119 100644 --- a/src/ftxui/dom/util.cpp +++ b/src/ftxui/dom/util.cpp @@ -1,4 +1,7 @@ -#include "ftxui/dom/elements.hpp" +#include // for function +#include // for move + +#include "ftxui/dom/elements.hpp" // for Decorator, Element, Elements, operator|, nothing namespace ftxui { diff --git a/src/ftxui/dom/vbox.cpp b/src/ftxui/dom/vbox.cpp index e514ae0c..06864982 100644 --- a/src/ftxui/dom/vbox.cpp +++ b/src/ftxui/dom/vbox.cpp @@ -1,8 +1,12 @@ -#include -#include +#include // for max +#include // for __shared_ptr_access, shared_ptr, make_shared +#include // for move +#include // for vector -#include "ftxui/dom/elements.hpp" -#include "ftxui/dom/node.hpp" +#include "ftxui/dom/elements.hpp" // for Element, Elements, vbox +#include "ftxui/dom/node.hpp" // for Node +#include "ftxui/dom/requirement.hpp" // for Requirement +#include "ftxui/screen/box.hpp" // for Box namespace ftxui { diff --git a/src/ftxui/dom/vbox_test.cpp b/src/ftxui/dom/vbox_test.cpp index 917afd9d..19aa8b9c 100644 --- a/src/ftxui/dom/vbox_test.cpp +++ b/src/ftxui/dom/vbox_test.cpp @@ -1,6 +1,14 @@ -#include "ftxui/dom/elements.hpp" -#include "ftxui/screen/screen.hpp" -#include "gtest/gtest.h" +#include // for Message +#include // for TestPartResult +#include // for remove +#include // for allocator, basic_string, string +#include // for vector + +#include "ftxui/dom/elements.hpp" // for vtext, operator|, Element, flex_grow +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui +#include "ftxui/screen/screen.hpp" // for Screen +#include "gtest/gtest_pred_impl.h" // for Test, SuiteApiResolver, EXPECT_EQ using namespace ftxui; using namespace ftxui; diff --git a/src/ftxui/screen/color.cpp b/src/ftxui/screen/color.cpp index e71547ee..ca2a4597 100644 --- a/src/ftxui/screen/color.cpp +++ b/src/ftxui/screen/color.cpp @@ -1,7 +1,4 @@ #include "ftxui/screen/color.hpp" - -#include - #include "ftxui/screen/color_info.hpp" #include "ftxui/screen/string.hpp" #include "ftxui/screen/terminal.hpp" diff --git a/src/ftxui/screen/color_info.cpp b/src/ftxui/screen/color_info.cpp index 2a12a2f6..a6300111 100644 --- a/src/ftxui/screen/color_info.cpp +++ b/src/ftxui/screen/color_info.cpp @@ -1,4 +1,5 @@ #include "ftxui/screen/color_info.hpp" +#include "ftxui/screen/color.hpp" // for Color, Color::Palette16, Color::Palette256 namespace ftxui { diff --git a/src/ftxui/screen/screen.cpp b/src/ftxui/screen/screen.cpp index 3485ee66..5a3dbd19 100644 --- a/src/ftxui/screen/screen.cpp +++ b/src/ftxui/screen/screen.cpp @@ -1,12 +1,12 @@ +#include // for min +#include // for operator<<, basic_ostream, wstringstream, stringstream, flush, cout, ostream +#include // IWYU pragma: keep + +#include "ftxui/dom/node.hpp" // for Element, Node +#include "ftxui/dom/requirement.hpp" // for Requirement #include "ftxui/screen/screen.hpp" - -#include -#include -#include - -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/string.hpp" -#include "ftxui/screen/terminal.hpp" +#include "ftxui/screen/string.hpp" // for to_string, wchar_width +#include "ftxui/screen/terminal.hpp" // for Terminal::Dimensions, Terminal #if defined(_WIN32) #define WIN32_LEAN_AND_MEAN @@ -169,9 +169,9 @@ std::string Screen::ToString() { auto width = wchar_width(c); if (width <= 0) { - // Avoid an infinite loop for non-printable characters - c = L' '; - width = 1; + // Avoid an infinite loop for non-printable characters + c = L' '; + width = 1; } ss << c; x += width; diff --git a/src/ftxui/screen/terminal.cpp b/src/ftxui/screen/terminal.cpp index e86c82df..7e202200 100644 --- a/src/ftxui/screen/terminal.cpp +++ b/src/ftxui/screen/terminal.cpp @@ -1,20 +1,17 @@ +#include // for getenv +#include // for string, allocator + #include "ftxui/screen/terminal.hpp" -#include - -#include - #if defined(_WIN32) #define WIN32_LEAN_AND_MEAN #define NOMINMAX #include #else -#include -#include +#include // for winsize, ioctl, TIOCGWINSZ +#include // for STDOUT_FILENO #endif -#include - namespace ftxui { Terminal::Dimensions Terminal::Size() { diff --git a/src/ftxui/screen/wcwidth.cpp b/src/ftxui/screen/wcwidth.cpp index 6d3bcdbc..7791a3e4 100644 --- a/src/ftxui/screen/wcwidth.cpp +++ b/src/ftxui/screen/wcwidth.cpp @@ -59,7 +59,7 @@ * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c */ -#include +#include #include "ftxui/screen/string.hpp" diff --git a/tools/iwyu.sh b/tools/iwyu.sh new file mode 100755 index 00000000..1e1f62b1 --- /dev/null +++ b/tools/iwyu.sh @@ -0,0 +1,11 @@ +#!/bin/bash +cd "$(dirname "$0")" +cd .. +mapping_dir=$(pwd) +mkdir -p iwyu +cd iwyu +rm * -rf +echo $CMAKE_CXX_INCLUDE_WHAT_YOU_USE +cmake .. -DFTXUI_BUILD_TESTS=ON -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="iwyu;-Xiwyu;--cxx17ns;-Xiwyu;--mapping_file=${mapping_dir}/iwyu.imp;-Xiwyu;--verbose=3" +make -j 2>out +fix_include --comments < out