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 57efcf4..b237613 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 194172c..d7f32da 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 ff779c0..41e3207 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 7a49f3e..57fa7b3 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 db1c25b..0775ad1 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 56820f3..68a1d18 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 887f27c..ad902bb 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 ed1495b..d35788e 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 67561ef..2fc712c 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 2d7ecd3..eb2a96d 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 dbf7f1e..78c8f46 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 ef6beb2..aa140a6 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 6485cf1..be565e8 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 3875945..11cbd5f 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 7ed3d14..adb1f38 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 e575868..f3bf1a3 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 392c62e..dfeea1d 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 52cfe87..7fff889 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 0445add..114a0d4 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 89cb641..e395d78 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 5c4ec50..f50fddb 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 53823a2..1c4d446 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 a180789..0ce864f 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 ad930ab..9a19181 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 41c5fd4..dedf04a 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 93bb984..92d23cd 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 18726da..df84561 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 0000000..fde820a --- /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 0000000..488c23c --- /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 7caba26..0c75202 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 130ce34..b4f3753 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 d4f6e0e..34fe2a5 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 cffa74a..917afd9 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 f98cc50..d83e424 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 fae1de8..e86c82d 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 b4f3753..4c3eb29 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 60c36da..35ef936 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 14e826a..40ab123 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 29fc9c1..5dc9e77 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 4c3eb29..36c4c54 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 78e0fdd..de73bd5 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 ac0df24..72fc095 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 35ef936..3cfd57f 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 40ab123..833ac7d 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 5dc9e77..d55d46b 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 de73bd5..f348aeb 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 72fc095..db13d59 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 b237613..92814d7 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 c734e75..76e4186 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 a92b8cd..f21121b 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 7054be1..03cee39 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 833ac7d..5c05578 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 ece6fe8..51fb148 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 aaf9828..bbfc6f7 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 bbe095c..846d11b 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 3019163..614b1c1 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 3a64302..719e1bd 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 581298e..8281268 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 9f9cfd9..ae3dc0c 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 4b55bcd..0fdd438 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 d55d46b..607ea7f 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 12b5ee3..a511493 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 ff7d169..7147c86 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 36c4c54..6b3365c 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 c7be19e..0437d00 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 0000000..10e7194 --- /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 b8ed1ee..07826f8 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 839d263..da1fb68 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 3cfd57f..fbd6ff8 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 5c05578..742c75c 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 51fb148..d621363 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 3327969..8f5903a 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 846d11b..8e9a3f6 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 8281268..85065c9 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 607ea7f..dac8951 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 a511493..c626f71 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 6b3365c..c149421 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 f348aeb..c566154 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 db13d59..bb63ad8 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 09bcfa4..80fbd29 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 0437d00..525cded 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 92814d7..a65cfd3 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 fbd6ff8..3ba9848 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 742c75c..bb87c6a 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 0000000..54e80d4 --- /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 85065c9..4da42dd 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 ae3dc0c..5fe251a 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 dac8951..2fa0cf0 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 c626f71..4eccfed 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 7147c86..d3ab38f 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 c149421..d95af0d 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 c566154..0864d74 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 bb63ad8..d378694 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 80fbd29..6212a1c 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 525cded..5c8b32e 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 fde820a..461adf2 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 9b92b83..a55bd30 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 7a76055..9ca7bcd 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 d95af0d..385271a 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 0864d74..b86d583 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 d83e424..3485ee6 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 a65cfd3..5b2d86b 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 5b2d86b..24214cf 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 10e7194..0ce40e4 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 a2b9e40..64b5f51 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 24214cf..3b79204 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 d20f899..07dc0b3 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 0000000..65cb068 --- /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 2b7af38..fcaf3f9 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 0000000..35a139d --- /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 0000000..894f9ee --- /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 3b79204..c6182a0 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 54f4d6c..9bd5c86 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 0000000..b76ac10 --- /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 fcaf3f9..5a42216 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 bb87c6a..6295c91 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 8f5903a..c61132c 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 35a139d..f9bff71 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 4da42dd..3ea1b77 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 5fe251a..8c04a08 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 9ca7bcd..d39ec1b 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 4eccfed..44f5f36 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 d3ab38f..7c50655 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 385271a..95cc26c 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 894f9ee..8ddb4fb 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 5c8b32e..8936096 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 64b5f51..1c60d40 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 c6182a0..e6fc342 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 3b089bc..efddeab 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 d38f4c1..dc3ceaf 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 a0cb0b8..47189b6 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 608f2d2..c1f0f96 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 9bd5c86..d819c54 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 ac8fc83..b6c49c7 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 2f2eb51..3fc69e1 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 1fd33e3..41860fe 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 dd422f6..91aacf8 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 da1fb68..3fc8879 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 520fd78..d325e49 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 62d0f1e..0a3a650 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 0137425..09c8644 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 65cb068..9e7b6f1 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 a475e4b..8d4b822 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 b32a8d9..398be13 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 ef2cd3a..5ecf092 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 57fa7b3..bd12701 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 0775ad1..8bdd3e7 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 68a1d18..0e172f4 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 ad902bb..0aa6317 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 d35788e..1fd632a 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 2fc712c..851e3ce 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 eb2a96d..ae882e8 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 78c8f46..55d6257 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 aa140a6..6d2cb9d 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 be565e8..4f60287 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 11cbd5f..1ae23b3 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 adb1f38..9a1a614 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 f3bf1a3..0f258a3 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 dfeea1d..bc736d4 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 7fff889..e5c3a26 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 114a0d4..64645bf 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 e395d78..df0dd6e 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 f50fddb..f96e3cc 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 1c4d446..61b73d7 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 0ce864f..4439aa6 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 9a19181..3712deb 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 dedf04a..52a8d7a 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 92d23cd..65b55a8 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 df84561..ea2e917 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 3ba9848..3f255b5 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 76e4186..e7b190c 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 b76ac10..9c69a3a 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 f21121b..214ce52 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 5a42216..9003f1c 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 03cee39..3f78798 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 6295c91..7da613e 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 a55bd30..fedeacb 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 d621363..8e3f2b1 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 54e80d4..aeeb490 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 bbfc6f7..7493245 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 7b85922..8b236c3 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 c61132c..c3a3251 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 f9bff71..6b30d42 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 8e9a3f6..bbdd1f1 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 614b1c1..073b783 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 7998da6..3ca5139 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 fecee23..3adf223 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 6bb0c19..e8edbcb 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 b3c64ca..5a35fc5 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 0000000..feaf961 --- /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 3ea1b77..357b594 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 8c04a08..a7382d8 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 d89de45..875d759 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 0fdd438..7c01a1d 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 86f36ae..da47638 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 2fa0cf0..b8bc436 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 d39ec1b..c9a9daa 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 44f5f36..90b1987 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 7c50655..4d6c00a 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 8fd5c2d..845dac0 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 8d06cc8..bd4e1cb 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 95cc26c..48bd747 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 8ddb4fb..122e523 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 b86d583..acab8e4 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 d378694..69645a6 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 6212a1c..b37b216 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 8936096..ca06461 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 acb19ef..4842d2c 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 8356d83..57a3a23 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 f959e81..1d5c3c7 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 2d14637..a7ce81c 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 da0c600..23fb36c 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 023dc8f..475d978 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 c818327..007057c 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 ea73791..e39283b 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 7b6b68a..296ea1d 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 bf2942e..303481c 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 7e25c8c..05f3ea9 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 d448036..fe45c4b 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 1056396..0eb3275 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 67f0cd3..4261bde 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 3ff91e0..43757e6 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 dbeac3a..fc5ca6c 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 ee6ff04..eb20233 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 1054990..c859546 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 d5f08c7..9ed078b 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 db5c39a..b98c2c2 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 0336b04..a9f1d4f 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 7a8a8e7..a90c18d 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 0ce40e4..79998ad 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 0997d6e..243249d 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 5bb4cb4..f5621b6 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 24ea38b..e415acc 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 0a30f7d..a8ade9a 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 34fe2a5..a1a5551 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 b04a110..7a3a50f 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 bc86b1b..1770611 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 e514ae0..0686498 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 917afd9..19aa8b9 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 e71547e..ca2a459 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 2a12a2f..a630011 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 3485ee6..5a3dbd1 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 e86c82d..7e20220 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 6d3bcdb..7791a3e 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 0000000..1e1f62b --- /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