diff --git a/.github/workflows/linux-emscripten.yaml b/.github/workflows/linux-emscripten.yaml index a2b9e40f9d094dcb1a9dfc6260028a78d52bca17..1c60d402486acc4f2fadc6c6324fd416d91e8012 100644 --- a/.github/workflows/linux-emscripten.yaml +++ b/.github/workflows/linux-emscripten.yaml @@ -16,6 +16,5 @@ jobs: run: > mkdir build; cd build; - emcmake cmake .. - -DFTXUI_BUILD_TESTS=ON; + emcmake cmake ..; cmake --build . --config Release; diff --git a/CMakeLists.txt b/CMakeLists.txt index 0831fbf51199ab5a535c9ebe5bf26cbadefe2c9a..f1cc6b97fbd8ca8347ffb884fb035fc92b16bd85 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) @@ -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 @@ -76,15 +77,18 @@ 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 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 + include/ftxui/component/slider.hpp include/ftxui/component/toggle.hpp src/ftxui/component/button.cpp src/ftxui/component/checkbox.cpp @@ -96,9 +100,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) @@ -107,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} @@ -199,7 +212,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/doc/example_list.md b/doc/example_list.md index 3b089bc0691af5579dd48279eb40b8803622f4bd..efddeab1cc4030892dc46331c46dae68199b165b 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/CMakeLists.txt b/examples/component/CMakeLists.txt index d20f8995337da33609da3112062c451b97df7956..07dc0b31e2d096808196572f871bc623f40edeed 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/button.cpp b/examples/component/button.cpp index d38f4c17172dec454413ea290d2cd6eeb8b4cfea..dc3ceaf16879d0631cce312e9a7696e28f395236 100644 --- a/examples/component/button.cpp +++ b/examples/component/button.cpp @@ -1,8 +1,14 @@ -#include "ftxui/component/button.hpp" - -#include "ftxui/component/component.hpp" -#include "ftxui/component/container.hpp" -#include "ftxui/component/screen_interactive.hpp" +#include <functional> // for function +#include <memory> // for unique_ptr, make_u... +#include <string> // for wstring +#include <utility> // for move +#include <vector> // 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/screen/box.hpp" // for ftxui using namespace ftxui; diff --git a/examples/component/checkbox.cpp b/examples/component/checkbox.cpp index a0cb0b8699e5a509f6f23c92fc626c9baf0a81c2..47189b640ee64bd7c44cfa63e7f1791dc757c788 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 608f2d2f4f3c1de12cdc83342cfac43fdf7c3993..c1f0f9616ee7ddf55f6391fcfc268c9eb270292c 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 <memory> // for allocator_traits<>... +#include <string> // for operator+, wstring +#include <utility> // for move +#include <vector> // 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 54f4d6cc42638f2beef1d2d2ff5eb2df6ac735bd..d819c54cfe21bd68abec1cbacafb6f471e752f53 100644 --- a/examples/component/gallery.cpp +++ b/examples/component/gallery.cpp @@ -1,11 +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/toggle.hpp" +#include <functional> // for function +#include <memory> // for allocator, unique_ptr +#include <string> // for wstring +#include <vector> // 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; @@ -20,6 +29,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 +70,26 @@ 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(), - }); + text(name) | size(WIDTH, EQUAL, 8), + separator(), + element | xflex, + }) | + xflex; + } + + Element Render(std::wstring name, Component& component) { + return Render(name, component.Render()); } Element Render() override { @@ -78,11 +103,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<void()> on_quit = [] {}; diff --git a/examples/component/homescreen.cpp b/examples/component/homescreen.cpp index ac8fc83beb63a8584e094dab54a296813ef8f57a..b6c49c798e52b1f5f632bdfa4adf0fb2e795ce18 100644 --- a/examples/component/homescreen.cpp +++ b/examples/component/homescreen.cpp @@ -1,14 +1,23 @@ -#include <cmath> -#include <thread> +#include <chrono> // for operator""s, chron... +#include <cmath> // for sin +#include <functional> // for ref, reference_wra... +#include <string> // for allocator, wstring +#include <thread> // for sleep_for, thread +#include <utility> // for move +#include <vector> // 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 2f2eb51ee691228b146580c9fae6a340bb24d74a..3fc69e1800cd66d873051dcd938767dc84666883 100644 --- a/examples/component/input.cpp +++ b/examples/component/input.cpp @@ -1,10 +1,6 @@ #include "ftxui/component/input.hpp" - -#include <iostream> - -#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 1fd33e3e2833e5a67719f1f8c451b7e949f084a3..41860fe425f5a43fe224032dff4ef32c8f3e7e75 100644 --- a/examples/component/menu.cpp +++ b/examples/component/menu.cpp @@ -1,10 +1,11 @@ -#include "ftxui/component/menu.hpp" +#include <functional> // for function +#include <iostream> // for basic_ostream::ope... +#include <string> // for wstring, allocator +#include <vector> // for vector -#include <chrono> -#include <iostream> -#include <thread> - -#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 dd422f6f3123ed89c2f6b8dde9e545524476821c..91aacf8e3b328e5ae7419e1cf40a09e84ee988af 100644 --- a/examples/component/menu2.cpp +++ b/examples/component/menu2.cpp @@ -1,11 +1,14 @@ -#include <chrono> -#include <iostream> -#include <thread> +#include <functional> // for function +#include <string> // for wstring, allocator +#include <vector> // 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 839d26303b4acff0b3671cef80d72797b8c6738b..3fc8879c9ef469cd2dc77bcc26f9b0505e2c0f7f 100644 --- a/examples/component/menu_style.cpp +++ b/examples/component/menu_style.cpp @@ -1,10 +1,15 @@ -#include <iostream> -#include <thread> +#include <functional> // for function +#include <initializer_list> // for initializer_list +#include <string> // for wstring, allocator +#include <vector> // 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", @@ -21,22 +33,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<void()> on_enter = []() {}; diff --git a/examples/component/modal_dialog.cpp b/examples/component/modal_dialog.cpp index 520fd78fd441975229cc593f0d838a8ff915a1fa..d325e4913d47a44d4815f2a60c1a7fac8c9965fc 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 <functional> // for function +#include <memory> // for allocator_traits<>... +#include <string> // for operator+, wstring +#include <vector> // 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 62d0f1ef98b54e08c0d952c31191f9f3089765f3..0a3a65079866d69c6c8a9a45a0ce6df7073f4adb 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 0137425fc8e9d5d82237f942b7940ce1becf3de2..09c86445c131334a3ad4913dd4b3a23b26472ea3 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 <string> // for wstring, operator+ +#include <vector> // 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 new file mode 100644 index 0000000000000000000000000000000000000000..9e7b6f13b27780edb4f6bb48e68aff412f811b4a --- /dev/null +++ b/examples/component/slider.cpp @@ -0,0 +1,84 @@ +#include <functional> // for function +#include <memory> // for allocator, unique_ptr +#include <string> // 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)); +} + +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<void(void)> 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<void(void)> 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/examples/component/tab_horizontal.cpp b/examples/component/tab_horizontal.cpp index a475e4bcf4f3fc62ce86433753a1fc733475088f..8d4b8225c7f56f9e2db79da49835afad93e43a08 100644 --- a/examples/component/tab_horizontal.cpp +++ b/examples/component/tab_horizontal.cpp @@ -1,11 +1,14 @@ -#include <iostream> -#include <thread> +#include <functional> // for function +#include <string> // for wstring, allocator +#include <vector> // 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 b32a8d9bb3c516d878867ff1fabeb79deff297c4..398be13dff4156e498299395f45f1dfdc2d94605 100644 --- a/examples/component/tab_vertical.cpp +++ b/examples/component/tab_vertical.cpp @@ -1,10 +1,12 @@ -#include <iostream> +#include <functional> // for function +#include <string> // for wstring, allocator +#include <vector> // 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 ef2cd3ab03e50655cd3f0acc7d9a37fd1243fc46..5ecf09209dcef86d40a8858dcdcda424583131b6 100644 --- a/examples/component/toggle.cpp +++ b/examples/component/toggle.cpp @@ -1,12 +1,7 @@ #include "ftxui/component/toggle.hpp" - -#include <chrono> -#include <iostream> -#include <thread> - -#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 57fa7b3a482f54823d78737e8f68effb70a5b045..bd1270125a86a83a51166148dc30933119bc241b 100644 --- a/examples/dom/border.cpp +++ b/examples/dom/border.cpp @@ -1,8 +1,9 @@ -#include <chrono> #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> -#include <iostream> -#include <thread> +#include <memory> + +#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 0775ad15dd8ebd239fb601a039bc26b5e04981c5..8bdd3e73369cb29cea7cf371a0e256b2c63cd5e5 100644 --- a/examples/dom/color_gallery.cpp +++ b/examples/dom/color_gallery.cpp @@ -1,14 +1,16 @@ -#include <cmath> #include <ftxui/dom/elements.hpp> #include <ftxui/screen/color_info.hpp> #include <ftxui/screen/screen.hpp> #include <ftxui/screen/terminal.hpp> -#include <iostream> - -#include "ftxui/screen/string.hpp" +#include <memory> +#include <utility> +#include <vector> 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 68a1d180f0ad7f526e1ad1db1effaf9d67182dc1..0e172f47f5cbe35707e143c1c7fdf6d73085ad78 100644 --- a/examples/dom/color_info_palette256.cpp +++ b/examples/dom/color_info_palette256.cpp @@ -1,10 +1,13 @@ -#include <algorithm> -#include <cmath> #include <ftxui/dom/elements.hpp> #include <ftxui/screen/color_info.hpp> #include <ftxui/screen/screen.hpp> -#include <ftxui/screen/terminal.hpp> -#include <iostream> +#include <string> +#include <utility> +#include <vector> + +#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 ad902bb0799c87880f860cde1b50a83b2af4a753..0aa63171411c2038229cb6ba05c98f135aff5771 100644 --- a/examples/dom/color_truecolor_HSV.cpp +++ b/examples/dom/color_truecolor_HSV.cpp @@ -1,10 +1,11 @@ -#include <cmath> #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> -#include <ftxui/screen/terminal.hpp> -#include <iostream> +#include <memory> +#include <utility> -#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 d35788e05fc602a229bcf6d65b32ecd123d6b56e..1fd632aeb9b22f3cdc9e2404a4c9a62d32c5edbe 100644 --- a/examples/dom/color_truecolor_RGB.cpp +++ b/examples/dom/color_truecolor_RGB.cpp @@ -1,10 +1,11 @@ -#include <cmath> #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> -#include <ftxui/screen/terminal.hpp> -#include <iostream> +#include <memory> +#include <utility> -#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 2fc712c6be6b24232b9ba08c07b276db6b5484c3..851e3ce4a76b1f7244631e6e74ea1f0777a897f9 100644 --- a/examples/dom/dbox.cpp +++ b/examples/dom/dbox.cpp @@ -1,6 +1,9 @@ #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> -#include <iostream> +#include <memory> + +#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 eb2a96ddbcbbf91d7d88fa5fe3450a027681c7cf..ae882e83384da1faf9d0f1ac0864c381f60bd508 100644 --- a/examples/dom/gauge.cpp +++ b/examples/dom/gauge.cpp @@ -2,8 +2,12 @@ #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> #include <iostream> +#include <string> #include <thread> +#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 78c8f468248a3b8a425b81dcdb9b1b8b40f31ef7..55d6257279f7378d0b072e28c9494e378770a607 100644 --- a/examples/dom/graph.cpp +++ b/examples/dom/graph.cpp @@ -2,9 +2,15 @@ #include <cmath> #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> -#include <ftxui/screen/string.hpp> +#include <functional> #include <iostream> +#include <string> #include <thread> +#include <vector> + +#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 aa140a634c980d7d033a5e9a13d427a63e28833e..6d2cb9dba08c61633c8fb8e0bf0933a0a18c76bc 100644 --- a/examples/dom/hflow.cpp +++ b/examples/dom/hflow.cpp @@ -1,7 +1,11 @@ +#include <stddef.h> #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> #include <ftxui/screen/string.hpp> -#include <iostream> +#include <string> + +#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 be565e8ecd596ec19b7c8b0535947027bb36eef4..4f602878cf5892ad914ed695982cbc045c13851e 100644 --- a/examples/dom/html_like.cpp +++ b/examples/dom/html_like.cpp @@ -1,10 +1,14 @@ #include <chrono> #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> -#include <ftxui/screen/string.hpp> #include <iostream> +#include <string> #include <thread> +#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 11cbd5f54455eea9269a74c695fed0eb45667227..1ae23b336cb54d606df257d69690ed2b8226e310 100644 --- a/examples/dom/package_manager.cpp +++ b/examples/dom/package_manager.cpp @@ -4,9 +4,16 @@ #include <ftxui/screen/string.hpp> #include <iostream> #include <list> +#include <memory> +#include <string> #include <thread> +#include <utility> #include <vector> +#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 adb1f38ff2bfbf4638397421288f2fa79cde771d..9a1a614a818ec56f4835aea4c8dd521044f7971f 100644 --- a/examples/dom/paragraph.cpp +++ b/examples/dom/paragraph.cpp @@ -1,7 +1,10 @@ +#include <stdio.h> #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> -#include <ftxui/screen/string.hpp> -#include <iostream> +#include <string> + +#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 f3bf1a315af80fe6ddc10c67857b6251b084d150..0f258a3490e840bc49f1db4ffa64310ca9d2d38f 100644 --- a/examples/dom/separator.cpp +++ b/examples/dom/separator.cpp @@ -1,6 +1,9 @@ #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> -#include <iostream> +#include <memory> + +#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 dfeea1d8a3ace0b7da3e4d5b553b4ea25e993b80..bc736d42556feeed1122c488166e654b694e2788 100644 --- a/examples/dom/size.cpp +++ b/examples/dom/size.cpp @@ -1,7 +1,12 @@ #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> #include <ftxui/screen/string.hpp> -#include <iostream> +#include <memory> +#include <string> +#include <utility> + +#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 7fff889e36964d537c3cf6e7af8af4b115cf405b..e5c3a262f5b6faa8feaa79ba08dd4f0a5dcff288 100644 --- a/examples/dom/spinner.cpp +++ b/examples/dom/spinner.cpp @@ -3,7 +3,13 @@ #include <ftxui/screen/screen.hpp> #include <ftxui/screen/string.hpp> #include <iostream> +#include <string> #include <thread> +#include <utility> +#include <vector> + +#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 114a0d4a242dab3b4273fbc063d75c5cf3aee04c..64645bf626935f76e4024fd98fd53b315d7c5cb1 100644 --- a/examples/dom/style_blink.cpp +++ b/examples/dom/style_blink.cpp @@ -1,6 +1,9 @@ #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> -#include <iostream> +#include <memory> + +#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 e395d7844ea2134e1c476f7a6aac732f4b32f2fd..df0dd6e346058f88ff0c24af2b52553601eb927f 100644 --- a/examples/dom/style_bold.cpp +++ b/examples/dom/style_bold.cpp @@ -1,6 +1,9 @@ #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> -#include <iostream> +#include <memory> + +#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 f50fddb355f748328bfd71b2f03afd2eeb76bdfd..f96e3ccf296e27ffa8b9faaf472abcb37b04e0ed 100644 --- a/examples/dom/style_color.cpp +++ b/examples/dom/style_color.cpp @@ -1,6 +1,10 @@ #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> -#include <iostream> +#include <memory> + +#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 1c4d4469192e1fc5cbbd98779c2f97bd48d31303..61b73d70285c514b66ee8c3b2b9e37a846510ed8 100644 --- a/examples/dom/style_dim.cpp +++ b/examples/dom/style_dim.cpp @@ -1,6 +1,9 @@ #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> -#include <iostream> +#include <memory> + +#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 0ce864f49f627c044fa1503c7aea896b20b890b0..4439aa637b0d6cf3d17b041ac6247bce600e66fb 100644 --- a/examples/dom/style_gallery.cpp +++ b/examples/dom/style_gallery.cpp @@ -1,6 +1,10 @@ #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> -#include <iostream> +#include <memory> + +#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 9a191810f8be07f057a2ce77807d23500183b24f..3712deba48c399ffe738d582e73eeb7820a73741 100644 --- a/examples/dom/style_inverted.cpp +++ b/examples/dom/style_inverted.cpp @@ -1,6 +1,9 @@ #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> -#include <iostream> +#include <memory> + +#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 dedf04ab831ae6c88ab0c7da2242e25ff0a4b9c5..52a8d7ad37f75ea3c3942195d7994409d339a56c 100644 --- a/examples/dom/style_underlined.cpp +++ b/examples/dom/style_underlined.cpp @@ -1,6 +1,9 @@ #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> -#include <iostream> +#include <memory> + +#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 92d23cdf60562d7ec1461668883e87b259027436..65b55a85baa4799ca6937a2ef062d7ecac35ac7f 100644 --- a/examples/dom/vbox_hbox.cpp +++ b/examples/dom/vbox_hbox.cpp @@ -1,6 +1,10 @@ +#include <stdio.h> #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> -#include <iostream> +#include <memory> + +#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 df8456175776885d3801bae238db62ac9ce69498..ea2e91724e28d54f521d829a60700044615bb082 100644 --- a/examples/dom/window.cpp +++ b/examples/dom/window.cpp @@ -1,6 +1,10 @@ #include <ftxui/dom/elements.hpp> #include <ftxui/screen/screen.hpp> -#include <iostream> +#include <vector> + +#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/index.html b/examples/index.html index fde820ac3c5cd2a9ceef5fc13b3014f678755a7d..4fd3e5c55c419385c67ea96689c78a179ad65dfd 100644 --- a/examples/index.html +++ b/examples/index.html @@ -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 = []; diff --git a/examples/util/print_key_press.cpp b/examples/util/print_key_press.cpp index 60c36da60a96b41bee9a1396447d991cf9333ef9..3f255b58876bacf68c84f89ee5594f0a0b5d390e 100644 --- a/examples/util/print_key_press.cpp +++ b/examples/util/print_key_press.cpp @@ -2,32 +2,83 @@ // Use of this source code is governed by the MIT license that can be found in // the LICENSE file. -#include <chrono> -#include <ftxui/component/component.hpp> -#include <ftxui/component/screen_interactive.hpp> -#include <ftxui/screen/string.hpp> -#include <iostream> -#include <thread> +#include <stddef.h> // for size_t +#include <algorithm> // for max +#include <ftxui/component/component.hpp> // for Component +#include <ftxui/component/screen_interactive.hpp> // for ScreenInteractive +#include <string> // for allocator, operator+ +#include <utility> // for move +#include <vector> // 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; +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; Element Render() override { Elements children; - for (size_t i = std::max(0, (int)keys.size() - 10); 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 += keys[i].character(); - else - code += L"(special)"; - children.push_back(text(code)); + for (size_t i = std::max(0, (int)keys.size() - 20); i < keys.size(); ++i) { + children.push_back(text(Stringify(keys[i]))); } return window(text(L"keys"), vbox(std::move(children))); } diff --git a/include/ftxui/component/button.hpp b/include/ftxui/component/button.hpp index c734e756d6d7114d5aa0e898ec92a7de41862694..e7b190c9ddc7714a4cc7a8698fa27b93d16aaf33 100644 --- a/include/ftxui/component/button.hpp +++ b/include/ftxui/component/button.hpp @@ -2,10 +2,14 @@ #define FTXUI_COMPONENT_BUTTON_HPP #include <functional> +#include <string> #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,9 @@ class Button : public Component { // Component implementation. Element Render() override; bool OnEvent(Event) override; + + private: + Box box_; }; } // namespace ftxui diff --git a/include/ftxui/component/captured_mouse.hpp b/include/ftxui/component/captured_mouse.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9c69a3af88de5a0227850b4a76fd91f4daf0ecd3 --- /dev/null +++ b/include/ftxui/component/captured_mouse.hpp @@ -0,0 +1,18 @@ +#ifndef FTXUI_CAPTURED_MOUSE_HPP +#define FTXUI_CAPTURED_MOUSE_HPP + +#include <memory> + +namespace ftxui { +class CapturedMouseInterface { + public: + virtual ~CapturedMouseInterface() {} +}; +using CapturedMouse = std::unique_ptr<CapturedMouseInterface>; +} // 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 a92b8cd3d158895c0772af71fc72adff8e90254b..214ce5241af9a0c0eb7c4f84891d8da5f16f8c09 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 <functional> +#include <string> #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. @@ -38,7 +40,10 @@ 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/component.hpp b/include/ftxui/component/component.hpp index 2b7af38e94359bc1c9b2c808e21b746b1d39cc99..9003f1c11f868cf4108eb2ee682179eedec66941 100644 --- a/include/ftxui/component/component.hpp +++ b/include/ftxui/component/component.hpp @@ -1,13 +1,17 @@ #ifndef FTXUI_COMPONENT_COMPONENT_HPP #define FTXUI_COMPONENT_COMPONENT_HPP -#include "ftxui/component/event.hpp" -#include "ftxui/dom/elements.hpp" +#include <memory> // for unique_ptr +#include <vector> // 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. @@ -51,15 +55,19 @@ class Component { // Configure all the ancestors to give focus to this component. void TakeFocus(); + protected: + CapturedMouse CaptureMouse(const Event& event); + + std::vector<Component*> children_; + private: Component* parent_ = nullptr; void Detach(); void Attach(Component* parent); - - protected: - std::vector<Component*> children_; }; +using ComponentPtr = std::unique_ptr<Component>; + } // namespace ftxui #endif /* end of include guard: FTXUI_COMPONENT_COMPONENT_HPP */ diff --git a/include/ftxui/component/container.hpp b/include/ftxui/component/container.hpp index 7054be194557ec935f9779e3f2b217cfd3644c01..3f78798fbf159862e722d8143b761d68ed80a105 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 { @@ -36,6 +38,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 b006f49f4fe7e183ec2d73cd1383cb8a9191ee61..e77feae937be7989d9659a3dc074de61e582ed4d 100644 --- a/include/ftxui/component/event.hpp +++ b/include/ftxui/component/event.hpp @@ -1,14 +1,15 @@ #ifndef FTXUI_COMPONENT_EVENT_HPP #define FTXUI_COMPONENT_EVENT_HPP -#include <array> -#include <ftxui/component/receiver.hpp> -#include <functional> -#include <string> +#include <ftxui/component/mouse.hpp> // for Mouse +#include <string> // for string, operator== #include <vector> namespace ftxui { +class ScreenInteractive; +class Component; + /// @brief Represent an event. It can be key press event, a terminal resize, or /// more ... /// @@ -26,8 +27,10 @@ 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 Mouse(std::string, Mouse mouse); + static Event CursorReporting(std::string, int x, int y); // --- Arrow --- static const Event ArrowLeft; @@ -54,8 +57,18 @@ 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() const { return type_ == Type::Mouse; } + struct Mouse& mouse() { + return mouse_; + } + + bool is_cursor_reporting() const { return type_ == Type::CursorReporting; } + 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_; } @@ -63,11 +76,30 @@ struct Event { //--- State section ---------------------------------------------------------- private: + friend Component; + friend ScreenInteractive; + enum class Type { + Unknown, + Character, + Mouse, + CursorReporting, + }; + Type type_ = Type::Unknown; + + struct Cursor { + int x; + int y; + }; + + union { + wchar_t character_ = U'?'; + struct Mouse mouse_; + struct Cursor cursor_; + }; std::string input_; - bool is_character_ = false; - wchar_t character_ = U'?'; -}; + ScreenInteractive* screen_ = nullptr; +}; } // namespace ftxui diff --git a/include/ftxui/component/input.hpp b/include/ftxui/component/input.hpp index 9b92b835abc5f432c65c133f41810c8e6192ffcc..fedeacbf5b7ce15587755a1c5b4162fb886bbeec 100644 --- a/include/ftxui/component/input.hpp +++ b/include/ftxui/component/input.hpp @@ -2,10 +2,14 @@ #define FTXUI_COMPONENT_INPUT_H_ #include <functional> +#include <string> #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. @@ -27,6 +31,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/include/ftxui/component/menu.hpp b/include/ftxui/component/menu.hpp index ece6fe89cbb08a7d8363db119ccc5da73fde5031..8e3f2b1637098d3e66269498bc5c11a18c5f3076 100644 --- a/include/ftxui/component/menu.hpp +++ b/include/ftxui/component/menu.hpp @@ -2,11 +2,15 @@ #define FTXUI_COMPONENT_MENU #include <functional> +#include <string> +#include <vector> #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 @@ -19,10 +23,12 @@ class Menu : public Component { // State. std::vector<std::wstring> 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<void()> on_change = []() {}; @@ -31,6 +37,11 @@ class Menu : public Component { // Component implementation. Element Render() override; bool OnEvent(Event) override; + + private: + bool OnMouseEvent(Event); + + std::vector<Box> boxes_; }; } // namespace ftxui diff --git a/include/ftxui/component/mouse.hpp b/include/ftxui/component/mouse.hpp new file mode 100644 index 0000000000000000000000000000000000000000..aeeb4909450c1bc11a8510c2a9c2724291c64915 --- /dev/null +++ b/include/ftxui/component/mouse.hpp @@ -0,0 +1,44 @@ +#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 +/// 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. +#endif /* end of include guard: FTXUI_COMPONENT_MOUSE_HPP */ diff --git a/include/ftxui/component/radiobox.hpp b/include/ftxui/component/radiobox.hpp index aaf9828af9d2126a239825a09552c23d43d932ff..749324508911da8122adca373c3f5b58bebb32b7 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 <functional> +#include <string> +#include <vector> #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. @@ -39,7 +43,9 @@ class RadioBox : public Component { bool OnEvent(Event) override; private: + bool OnMouseEvent(Event event); int cursor_position = 0; + std::vector<Box> boxes_; }; } // namespace ftxui diff --git a/include/ftxui/component/receiver.hpp b/include/ftxui/component/receiver.hpp index 7b85922410f1d6f81d91bd675ac1cb5396921753..8b236c3587da6c0dd4ed4e5d6c97d77f27e9f2e9 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 <atomic> -#include <condition_variable> +#include <atomic> // for atomic +#include <condition_variable> // for condition_variable #include <functional> #include <iostream> -#include <memory> -#include <mutex> -#include <queue> +#include <memory> // for unique_ptr, make_unique +#include <mutex> // for mutex, unique_lock +#include <queue> // for queue namespace ftxui { @@ -38,6 +38,7 @@ namespace ftxui { // clang-format off template<class T> class SenderImpl; template<class T> class ReceiverImpl; + template<class T> using Sender = std::unique_ptr<SenderImpl<T>>; template<class T> using Receiver = std::unique_ptr<ReceiverImpl<T>>; template<class T> Receiver<T> MakeReceiver(); diff --git a/include/ftxui/component/screen_interactive.hpp b/include/ftxui/component/screen_interactive.hpp index 3327969789c6cecdc8fd0caae9e01e85dce102c4..c3a3251923a80d12841bd74d62a7cc4c3111beba 100644 --- a/include/ftxui/component/screen_interactive.hpp +++ b/include/ftxui/component/screen_interactive.hpp @@ -1,19 +1,18 @@ #ifndef FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP #define FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP -#include <atomic> -#include <condition_variable> +#include <atomic> // for atomic #include <ftxui/component/receiver.hpp> -#include <functional> -#include <memory> -#include <mutex> -#include <queue> +#include <memory> // for unique_ptr +#include <string> // for string +#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: @@ -27,6 +26,7 @@ class ScreenInteractive : public Screen { std::function<void()> ExitLoopClosure(); void PostEvent(Event event); + CapturedMouse CaptureMouse(); private: void Draw(Component* component); @@ -52,6 +52,11 @@ class ScreenInteractive : public Screen { std::string reset_cursor_position; std::atomic<bool> quit_ = false; + + 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 new file mode 100644 index 0000000000000000000000000000000000000000..6b30d4272a84e648d8089e84a3ba7419ee67c49d --- /dev/null +++ b/include/ftxui/component/slider.hpp @@ -0,0 +1,23 @@ +#ifndef FTXUI_COMPONENT_SLIDER_HPP +#define FTXUI_COMPONENT_SLIDER_HPP + +#include <string> +#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); + +template <class T> // T = {int, float} +ComponentPtr Slider(std::wstring label, T* value, T min, T max, T 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/include/ftxui/component/toggle.hpp b/include/ftxui/component/toggle.hpp index bbe095c7d1e5df462f1e54719095d9851ff7c71d..bbdd1f1d1dc019c26d57aac863a89bb5af15399c 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 <functional> #include <string> +#include <vector> #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 @@ -16,12 +19,14 @@ class Toggle : public Component { ~Toggle() override = default; // State. - int selected = 0; std::vector<std::wstring> 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<void()> on_change = []() {}; @@ -30,6 +35,10 @@ class Toggle : public Component { // Component implementation. Element Render() override; bool OnEvent(Event) override; + + private: + bool OnMouseEvent(Event event); + std::vector<Box> boxes_; }; } // namespace ftxui diff --git a/include/ftxui/dom/elements.hpp b/include/ftxui/dom/elements.hpp index 30191635ff648b07b3c3ecde396b0005444f155a..073b78338dce20aadf3e27b17bc901d353b3bc29 100644 --- a/include/ftxui/dom/elements.hpp +++ b/include/ftxui/dom/elements.hpp @@ -5,6 +5,7 @@ #include <memory> #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/dom/node.hpp b/include/ftxui/dom/node.hpp index 7998da6b66e1021953d82237e17d6e3e82b47d7e..3ca51394e8e392409b3db2b0e4c992736b4b6e1d 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 <memory> -#include <vector> +#include <memory> // for shared_ptr +#include <vector> // 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<Node>; using Elements = std::vector<std::shared_ptr<Node>>; diff --git a/include/ftxui/dom/take_any_args.hpp b/include/ftxui/dom/take_any_args.hpp index fecee2389b355efbdb44c2f71fd411288e385217..3adf2237b3cd17f782b77c116a430a2e549a4e45 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 <type_traits> template <class T> diff --git a/include/ftxui/screen/box.hpp b/include/ftxui/screen/box.hpp index 3a643027a5559728d375fe5c3c86fc2d43acf5a6..719e1bd5df5470a52af3e1d38bbaa73ed334a3eb 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/include/ftxui/screen/color.hpp b/include/ftxui/screen/color.hpp index 6bb0c19b738a4d00a5461a6a7863ae73d4cec6cf..e8edbcb82c8b9c5fdac9a9741f6946951e48e0cf 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 <cstdint> -#include <string> +#include <stdint.h> // for uint8_t +#include <string> // 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 b3c64ca418f7915f7e5640c7ce758a94f108e4d1..5a35fc5bf728c1edf4e5cc0dee9e9fee97f2210b 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 <stdint.h> #include <ftxui/screen/color.hpp> namespace ftxui { diff --git a/iwyu.imp b/iwyu.imp new file mode 100644 index 0000000000000000000000000000000000000000..feaf961bd2c25e4d2fb95093125117f35dd317c3 --- /dev/null +++ b/iwyu.imp @@ -0,0 +1,8 @@ +[ + { symbol: [ "VMIN", private, "<termios.h>", public ] }, + { symbol: [ "VTIME", private, "<termios.h>", public ] }, + { symbol: [ "ECHO", private, "<termios.h>", public ] }, + { symbol: [ "ICANON", private, "<termios.h>", public ] }, + { symbol: [ "termios", private, "<termios.h>", public ] }, + { symbol: [ "TCSANOW", private, "<termios.h>", public ] }, +] diff --git a/src/ftxui/component/button.cpp b/src/ftxui/component/button.cpp index 581298ec77c872e038ecff576a000dae0b569838..357b5945ebb4458bae96af4a33cfe0eb3e009fe2 100644 --- a/src/ftxui/component/button.cpp +++ b/src/ftxui/component/button.cpp @@ -1,17 +1,35 @@ -#include "ftxui/component/button.hpp" +#include <functional> // for function +#include <memory> // for shared_ptr -#include <functional> +#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 { Element Button::Render() { - if (Focused()) - return text(label) | border | inverted; - else - return text(label) | border; + auto style = Focused() ? inverted : nothing; + return text(label) | border | style | reflect(box_); } bool Button::OnEvent(Event event) { + if (event.is_mouse() && box_.Contain(event.mouse().x, event.mouse().y)) { + if (!CaptureMouse(event)) + return false; + + TakeFocus(); + + if (event.mouse().button == Mouse::Left && + event.mouse().motion == Mouse::Pressed) { + 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 9f9cfd96b83aaea2d0a2853e575974c204d50ef7..a7382d87e2a5244d418c8b9d59d07e4a70838e22 100644 --- a/src/ftxui/component/checkbox.cpp +++ b/src/ftxui/component/checkbox.cpp @@ -1,6 +1,11 @@ -#include "ftxui/component/checkbox.hpp" +#include <functional> // for function +#include <memory> // for shared_ptr -#include <functional> +#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 { @@ -9,10 +14,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 +30,24 @@ bool CheckBox::OnEvent(Event event) { return false; } +bool CheckBox::OnMouseEvent(Event event) { + if (!CaptureMouse(event)) + return false; + if (!box_.Contain(event.mouse().x, event.mouse().y)) + return false; + + TakeFocus(); + + if (event.mouse().button == Mouse::Left && + event.mouse().motion == Mouse::Pressed) { + state = !state; + on_change(); + return true; + } + + return false; +} + } // namespace ftxui // Copyright 2020 Arthur Sonzogni. All rights reserved. diff --git a/src/ftxui/component/component.cpp b/src/ftxui/component/component.cpp index d89de450e496a84640ea75d72edb25296738354b..875d759f8f96be1b4bea2147f146ca4aa81f365f 100644 --- a/src/ftxui/component/component.cpp +++ b/src/ftxui/component/component.cpp @@ -1,11 +1,20 @@ #include "ftxui/component/component.hpp" -#include <assert.h> - #include <algorithm> +#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<CaptureMouseImpl>(); + 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 4b55bcd8e7815eef060f42173f870810bd5e102f..7c01a1d02b28092375a1db5d6b08efb41910ac8c 100644 --- a/src/ftxui/component/container.cpp +++ b/src/ftxui/component/container.cpp @@ -1,6 +1,8 @@ #include "ftxui/component/container.hpp" +#include <stddef.h> #include <algorithm> +#include <vector> namespace ftxui { @@ -30,6 +32,9 @@ Container Container::Tab(int* selector) { } bool Container::OnEvent(Event event) { + if (event.is_mouse()) + return OnMouseEvent(event); + if (!Focused()) return false; @@ -115,6 +120,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/container_test.cpp b/src/ftxui/component/container_test.cpp index 86f36aec83fa7ac6f405be2b04abf1e377d3bb9d..da47638ce89859d4011a402e92af6ca212b2d58b 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 <gtest/gtest-message.h> // for Message +#include <gtest/gtest-test-part.h> // for TestPartResult, SuiteApiResolver +#include <memory> // 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 b8c6d7a40427c40ee1f87f7f44920be80f49af18..6987368fa13443b5c292e0087e54e196806fd0c3 100644 --- a/src/ftxui/component/event.cpp +++ b/src/ftxui/component/event.cpp @@ -1,16 +1,16 @@ #include "ftxui/component/event.hpp" -#include <iostream> +#include "ftxui/component/mouse.hpp" #include "ftxui/screen/string.hpp" 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,15 +23,34 @@ 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::Mouse(std::string input, struct Mouse mouse) { + Event event; + event.input_ = std::move(input); + event.type_ = Type::Mouse; + event.mouse_ = mouse; + return event; +} + +// static +Event Event::Special(std::string input) { + Event event; + event.input_ = std::move(input); + return event; +} + +// static +Event Event::CursorReporting(std::string input, int x, int y) { Event event; event.input_ = std::move(input); + event.type_ = Type::CursorReporting; + event.cursor_.x = x; + event.cursor_.y = y; return event; } diff --git a/src/ftxui/component/input.cpp b/src/ftxui/component/input.cpp index 0223c941ea7f4262f70d18e120bca14a0de320f9..5097bbda62140512c6a2b78ab70124c4b94639ab 100644 --- a/src/ftxui/component/input.cpp +++ b/src/ftxui/component/input.cpp @@ -1,8 +1,11 @@ #include "ftxui/component/input.hpp" #include <algorithm> +#include <memory> -#include "ftxui/screen/string.hpp" +#include "ftxui/component/captured_mouse.hpp" +#include "ftxui/component/mouse.hpp" +#include "ftxui/component/screen_interactive.hpp" namespace ftxui { @@ -15,14 +18,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 +41,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<int>(content.size(), cursor_position)); + + if (event.is_mouse()) + return OnMouseEvent(event); + std::wstring c; // Backspace. @@ -105,6 +114,28 @@ bool Input::OnEvent(Event event) { return false; } +bool Input::OnMouseEvent(Event event) { + if (!CaptureMouse(event)) + return false; + 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<int>(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/input_test.cpp b/src/ftxui/component/input_test.cpp index 4bfc6b95fc3e4952fa512d53d4dd3262e476ce77..7f4fa50327b1f6b97f52a4efef851b1d6a3ce97a 100644 --- a/src/ftxui/component/input_test.cpp +++ b/src/ftxui/component/input_test.cpp @@ -1,4 +1,5 @@ #include "ftxui/component/input.hpp" +#include "ftxui/component/event.hpp" #include "gtest/gtest.h" diff --git a/src/ftxui/component/menu.cpp b/src/ftxui/component/menu.cpp index 12b5ee3470b9d2d0fce12eca4e6803e33334978a..90b19878286eadb8525e32f081a30d9c4b75aa4c 100644 --- a/src/ftxui/component/menu.cpp +++ b/src/ftxui/component/menu.cpp @@ -1,25 +1,43 @@ #include "ftxui/component/menu.hpp" +#include <stddef.h> #include <algorithm> -#include <iostream> +#include <memory> +#include <utility> + +#include "ftxui/component/captured_mouse.hpp" +#include "ftxui/component/mouse.hpp" +#include "ftxui/component/screen_interactive.hpp" namespace ftxui { Element Menu::Render() { - std::vector<Element> 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)); } bool Menu::OnEvent(Event event) { + if (!CaptureMouse(event)) + return false; + if (event.is_mouse()) + return OnMouseEvent(event); + if (!Focused()) return false; @@ -36,6 +54,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; } @@ -48,6 +67,27 @@ bool Menu::OnEvent(Event event) { return false; } +bool Menu::OnMouseEvent(Event event) { + if (!CaptureMouse(event)) + return false; + for (int i = 0; i < boxes_.size(); ++i) { + if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) + continue; + + TakeFocus(); + focused = i; + if (event.mouse().button == Mouse::Left && + event.mouse().motion == Mouse::Released) { + 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/radiobox.cpp b/src/ftxui/component/radiobox.cpp index ff7d169f82747cb33fa6e3ee1201eecebac74390..4d6c00a20aef71d6c5eeabc199488899dacafefa 100644 --- a/src/ftxui/component/radiobox.cpp +++ b/src/ftxui/component/radiobox.cpp @@ -1,27 +1,41 @@ #include "ftxui/component/radiobox.hpp" +#include <stddef.h> #include <algorithm> #include <functional> +#include <memory> +#include <utility> + +#include "ftxui/component/captured_mouse.hpp" +#include "ftxui/component/mouse.hpp" +#include "ftxui/component/screen_interactive.hpp" namespace ftxui { Element RadioBox::Render() { std::vector<Element> 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; - 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) | - focus_management); + focus_management | reflect(boxes_[i])); } return vbox(std::move(elements)); } bool RadioBox::OnEvent(Event event) { + if (!CaptureMouse(event)) + return false; + if (event.is_mouse()) + return OnMouseEvent(event); + if (!Focused()) return false; @@ -50,6 +64,30 @@ bool RadioBox::OnEvent(Event event) { return false; } +bool RadioBox::OnMouseEvent(Event event) { + if (!CaptureMouse(event)) + return false; + for (int i = 0; i < boxes_.size(); ++i) { + if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) + continue; + + focused = i; + TakeFocus(); + + if (event.mouse().button == Mouse::Left && + event.mouse().motion == Mouse::Pressed) { + 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/radiobox_test.cpp b/src/ftxui/component/radiobox_test.cpp index 8fd5c2d36afbb326afe244f9bfdebf7b36d549f6..845dac0f15e0b7b006dad5ee43ee7bfc6ae56fff 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 <gtest/gtest-message.h> // for Message +#include <gtest/gtest-test-part.h> // 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 8d06cc8eb9aeed1bd488040102a136766a29b66f..bd4e1cb63e2cede715b98f9348f875897085d882 100644 --- a/src/ftxui/component/receiver_test.cpp +++ b/src/ftxui/component/receiver_test.cpp @@ -1,8 +1,10 @@ -#include "ftxui/component/receiver.hpp" - -#include <thread> +#include <gtest/gtest-message.h> // for Message +#include <gtest/gtest-test-part.h> // for TestPartResult +#include <thread> // for thread +#include <utility> // for move -#include "gtest/gtest.h" +#include "ftxui/component/receiver.hpp" +#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 b4f3753b4b51f43b249617b74a9b88ff0f546084..c02dccf76ad0dd4731970e76d302df85b2313ed1 100644 --- a/src/ftxui/component/screen_interactive.cpp +++ b/src/ftxui/component/screen_interactive.cpp @@ -1,18 +1,24 @@ #include "ftxui/component/screen_interactive.hpp" -#include <stdio.h> - -#include <algorithm> -#include <csignal> -#include <cstdlib> -#include <iostream> -#include <stack> -#include <thread> - -#include "ftxui/component/component.hpp" -#include "ftxui/component/terminal_input_parser.hpp" -#include "ftxui/screen/string.hpp" -#include "ftxui/screen/terminal.hpp" +#include <stdio.h> // for fileno, stdin +#include <algorithm> // for copy, max, min +#include <csignal> // for signal, SIGINT +#include <cstdlib> // for exit, NULL +#include <iostream> // for cout, ostream +#include <stack> // for stack +#include <thread> // for thread +#include <utility> // for move +#include <vector> // for vector + +#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 @@ -25,8 +31,9 @@ #error Must be compiled in UNICODE mode #endif #else -#include <termios.h> -#include <unistd.h> +#include <sys/select.h> // for select, FD_ISSET +#include <termios.h> // for tcsetattr, tcge... +#include <unistd.h> // for STDIN_FILENO, read #endif // Quick exit is missing in standard CLang headers @@ -40,15 +47,14 @@ 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; constexpr int timeout_microseconds = timeout_milliseconds * 1000; #if defined(_WIN32) -void EventListener(std::atomic<bool>* quit, - Sender<Event> out) { +void EventListener(std::atomic<bool>* quit, Sender<Event> out) { auto console = GetStdHandle(STD_INPUT_HANDLE); auto parser = TerminalInputParser(out->Clone()); while (!*quit) { @@ -68,8 +74,7 @@ void EventListener(std::atomic<bool>* quit, std::vector<INPUT_RECORD> 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); @@ -114,7 +119,7 @@ void EventListener(std::atomic<bool>* quit, Sender<Event> out) { } #else -#include <sys/time.h> +#include <sys/time.h> // for timeval int CheckStdinReady(int usec_timeout) { timeval tv = {0, usec_timeout}; @@ -146,14 +151,53 @@ void EventListener(std::atomic<bool>* quit, Sender<Event> out) { #endif -static const char* HIDE_CURSOR = "\x1B[?25l"; -static const char* SHOW_CURSOR = "\x1B[?25h"; +const std::string CSI = "\x1b["; + +// 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, +}; + +// Device Status Report (DSR) { +enum class DSRMode { + kCursor = 6, +}; + +const std::string Serialize(std::vector<DECMode> parameters) { + bool first = true; + std::string out; + for (DECMode parameter : parameters) { + if (!first) + out += ";"; + out += std::to_string(int(parameter)); + first = false; + } + return out; +} + +// DEC Private Mode Set (DECSET) +const std::string Set(std::vector<DECMode> parameters) { + return CSI + "?" + Serialize(parameters) + "h"; +} -static const char* DISABLE_LINE_WRAP = "\x1B[7l"; -static const char* ENABLE_LINE_WRAP = "\x1B[7h"; +// DEC Private Mode Reset (DECRST) +const std::string Reset(std::vector<DECMode> parameters) { + return CSI + "?" + Serialize(parameters) + "l"; +} -static const char* USE_ALTERNATIVE_SCREEN = "\x1B[?1049h"; -static const char* USE_NORMAL_SCREEN = "\x1B[?1049l"; +// Device Status Report (DSR) +const std::string DeviceStatusReport(DSRMode ps) { + return CSI + std::to_string(int(ps)) + "n"; +} using SignalHandler = void(int); std::stack<std::function<void()>> on_exit_functions; @@ -177,6 +221,15 @@ void OnResize(int /* signal */) { on_resize(); } +class CapturedMouseImpl : public CapturedMouseInterface { + public: + CapturedMouseImpl(std::function<void(void)> callback) : callback_(callback) {} + ~CapturedMouseImpl() override { callback_(); } + + private: + std::function<void(void)> callback_; +}; + } // namespace ScreenInteractive::ScreenInteractive(int dimx, @@ -217,6 +270,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<CapturedMouseImpl>( + [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); @@ -274,23 +335,48 @@ 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<DECMode> parameters) { + std::cout << Set(parameters); + on_exit_functions.push([=] { std::cout << Reset(parameters); }); + }; + + auto disable = [&](std::vector<DECMode> 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, + }); } - // 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(); + // On exit, reset cursor one line after the current drawing. + on_exit_functions.push( + [=] { std::cout << reset_cursor_position << std::endl; }); + + disable({ + DECMode::kCursor, + DECMode::kLineWrap, + }); + + enable({ + // DECMode::kMouseVt200, + DECMode::kMouseAnyEvent, + DECMode::kMouseUtf8, + DECMode::kMouseSgrExtMode, }); + flush(); + auto event_listener = std::thread(&EventListener, &quit_, event_receiver_->MakeSender()); @@ -298,14 +384,33 @@ void ScreenInteractive::Loop(Component* component) { while (!quit_) { if (!event_receiver_->HasPending()) { std::cout << reset_cursor_position << ResetPosition(); + static int i = -2; + if (i % 10 == 0) + std::cout << DeviceStatusReport(DSRMode::kCursor); + ++i; Draw(component); std::cout << ToString() << set_cursor_position; Flush(); Clear(); } + Event event; - if (event_receiver_->Receive(&event)) - component->OnEvent(event); + if (!event_receiver_->Receive(&event)) + break; + + if (event.is_cursor_reporting()) { + cursor_x_ = event.cursor_x(); + cursor_y_ = event.cursor_y(); + continue; + } + + if (event.is_mouse()) { + event.mouse().x -= cursor_x_; + event.mouse().y -= cursor_y_; + } + + event.screen_ = this; + component->OnEvent(event); } event_listener.join(); diff --git a/src/ftxui/component/slider.cpp b/src/ftxui/component/slider.cpp new file mode 100644 index 0000000000000000000000000000000000000000..122e523b1b45972c3ae69c0d87c1f2d96b8fd623 --- /dev/null +++ b/src/ftxui/component/slider.cpp @@ -0,0 +1,119 @@ +#include "ftxui/component/slider.hpp" + +#include <memory> +#include <utility> + +#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 <class T> +class SliderImpl : public Component { + public: + SliderImpl(std::wstring label, T* value, T min, T max, T 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 (captured_mouse_ && event.mouse().motion == Mouse::Released) { + captured_mouse_ = nullptr; + return true; + } + + if (box_.Contain(event.mouse().x, event.mouse().y) && + CaptureMouse(event)) { + 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_ = CaptureMouse(event); + } + + 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_; + T* value_; + T min_; + T max_; + T increment_ = 1; + Box box_; + Box gauge_box_; + CapturedMouse captured_mouse_; +}; + +template <class T> +ComponentPtr Slider(std::wstring label, T* value, T min, T max, T increment) { + return std::make_unique<SliderImpl<T>>(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 + +// 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 78e0fdda86b5cb7a8332e1c3b2c01d4423d10276..acab8e4b6256d38b93b1fd903fa26f57ac88cad2 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 <utility> +#include "ftxui/component/event.hpp" + namespace ftxui { TerminalInputParser::TerminalInputParser(Sender<Event> out) @@ -30,8 +33,8 @@ 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; @@ -48,10 +51,22 @@ void TerminalInputParser::Send(TerminalInputParser::Type type) { 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(). } -TerminalInputParser::Type TerminalInputParser::Parse() { +TerminalInputParser::Output TerminalInputParser::Parse() { if (!Eat()) return UNCOMPLETED; @@ -75,7 +90,7 @@ TerminalInputParser::Type TerminalInputParser::Parse() { return ParseUTF8(); } -TerminalInputParser::Type TerminalInputParser::ParseUTF8() { +TerminalInputParser::Output TerminalInputParser::ParseUTF8() { unsigned char head = static_cast<unsigned char>(Current()); for (int i = 0; i < 3; ++i, head <<= 1) { if ((head & 0b11000000) != 0b11000000) @@ -86,7 +101,7 @@ TerminalInputParser::Type TerminalInputParser::ParseUTF8() { return CHARACTER; } -TerminalInputParser::Type TerminalInputParser::ParseESC() { +TerminalInputParser::Output TerminalInputParser::ParseESC() { if (!Eat()) return UNCOMPLETED; switch (Current()) { @@ -103,7 +118,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 +137,45 @@ TerminalInputParser::Type TerminalInputParser::ParseDCS() { } } -TerminalInputParser::Type TerminalInputParser::ParseCSI() { +TerminalInputParser::Output TerminalInputParser::ParseCSI() { + bool altered = false; + int argument = 0; + std::vector<int> arguments; while (true) { if (!Eat()) return UNCOMPLETED; - if (Current() >= '0' && Current() <= '9') + if (Current() == '<') { + altered = true; continue; + } - if (Current() == ';') + if (Current() >= '0' && Current() <= '9') { + argument *= 10; + argument += int(Current() - '0'); continue; + } - if (Current() >= ' ' && Current() <= '~') - return SPECIAL; + if (Current() == ';') { + arguments.push_back(argument); + argument = 0; + continue; + } + + if (Current() >= ' ' && Current() <= '~' && Current() != '<') { + arguments.push_back(argument); + argument = 0; + switch (Current()) { + case 'M': + return ParseMouse(altered, true, std::move(arguments)); + case 'm': + return ParseMouse(altered, false, std::move(arguments)); + case 'R': + return ParseCursorReporting(std::move(arguments)); + default: + return SPECIAL; + } + } // Invalid ESC in CSI. if (Current() == '\x1B') @@ -142,7 +183,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 +197,39 @@ TerminalInputParser::Type TerminalInputParser::ParseOSC() { return SPECIAL; } } + +TerminalInputParser::Output TerminalInputParser::ParseMouse( + bool altered, + bool pressed, + std::vector<int> arguments) { + if (arguments.size() != 3) + return SPECIAL; + + (void)altered; + + Output output(MOUSE); + output.mouse.button = Mouse::Button((arguments[0] & 3) + // + ((arguments[0] & 64) >> 4)); + output.mouse.motion = Mouse::Motion(pressed); + output.mouse.shift = bool(arguments[0] & 4); + output.mouse.meta = bool(arguments[0] & 8); + output.mouse.x = arguments[1]; + output.mouse.y = arguments[2]; + return output; +} + +TerminalInputParser::Output TerminalInputParser::ParseCursorReporting( + std::vector<int> arguments) { + if (arguments.size() != 2) + return SPECIAL; + Output output(CURSOR_REPORTING); + output.cursor.y = arguments[0]; + output.cursor.x = arguments[1]; + return output; +} + } // 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 ac0df243d00d5a63db61197ea65186fd547dcc8e..69645a6a386717d9d9cdd278d416ebcb300fe9f1 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 <memory> // for unique_ptr +#include <string> // for string +#include <vector> // for vector -#include <string> +#include "ftxui/component/event.hpp" // IWYU pragma: keep +#include "ftxui/component/mouse.hpp" // for Mouse +#include "ftxui/component/receiver.hpp" // for SenderImpl namespace ftxui { @@ -20,18 +23,38 @@ class TerminalInputParser { bool Eat(); enum Type { - UNCOMPLETED = 0, - DROP = 1, - CHARACTER = 2, - SPECIAL = 3, + UNCOMPLETED, + DROP, + CHARACTER, + SPECIAL, + MOUSE, + CURSOR_REPORTING, }; - void Send(Type type); - Type Parse(); - Type ParseUTF8(); - Type ParseESC(); - Type ParseDCS(); - Type ParseCSI(); - Type ParseOSC(); + + struct CursorReporting { + int x; + int y; + }; + + struct Output { + Type type; + union { + Mouse mouse; + CursorReporting cursor; + }; + + Output(Type type) : type(type) {} + }; + + void Send(Output type); + Output Parse(); + Output ParseUTF8(); + Output ParseESC(); + Output ParseDCS(); + Output ParseCSI(); + Output ParseOSC(); + Output ParseMouse(bool altered, bool pressed, std::vector<int> arguments); + Output ParseCursorReporting(std::vector<int> arguments); Sender<Event> 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 09bcfa40881794e34ff1421ad6a74561bb3787a5..b37b21634160b2e0e207657679219486419edb77 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 <gtest/gtest-message.h> // for Message +#include <gtest/gtest-test-part.h> // 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; @@ -66,6 +68,84 @@ TEST(Event, EscapeKeyEnoughWait) { EXPECT_FALSE(event_receiver->Receive(&received)); } +TEST(Event, MouseLeftClick) { + auto event_receiver = MakeReceiver<Event>(); + { + auto parser = TerminalInputParser(event_receiver->MakeSender()); + parser.Add('\x1B'); + parser.Add('['); + 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<Event>(); + { + 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<Event>(); + { + 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)); +} + // 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 c7be19e28ffc9be77da25542b8da323bb7476576..ca064617694b686fa096c7f9f84e3edbf20fea48 100644 --- a/src/ftxui/component/toggle.cpp +++ b/src/ftxui/component/toggle.cpp @@ -1,29 +1,43 @@ -#include "ftxui/component/toggle.hpp" +#include <stddef.h> // for size_t +#include <algorithm> // for max, min +#include <memory> // for shared_ptr, alloca... +#include <utility> // for move -#include <algorithm> +#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 { Element Toggle::Render() { - bool is_focused = Focused(); - 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); + 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)); } 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--; @@ -37,6 +51,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; } @@ -49,6 +64,28 @@ bool Toggle::OnEvent(Event event) { return false; } +bool Toggle::OnMouseEvent(Event event) { + if (!CaptureMouse(event)) + return false; + for (int i = 0; i < boxes_.size(); ++i) { + if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) + continue; + + TakeFocus(); + focused = i; + if (event.mouse().button == Mouse::Left && + event.mouse().motion == Mouse::Pressed) { + 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/toggle_test.cpp b/src/ftxui/component/toggle_test.cpp index acb19ef3e430f9bfef28aeb8b8e34865ea6d25c0..4842d2c06d2bfe7ef02d20431190d1c434bb31e0 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 <gtest/gtest-message.h> // for Message +#include <gtest/gtest-test-part.h> // 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 8356d836bb2dcbe733a66574af92c7642e2ea7f9..57a3a2304c40021dd00de41afc236687aad6b42b 100644 --- a/src/ftxui/dom/blink.cpp +++ b/src/ftxui/dom/blink.cpp @@ -1,5 +1,10 @@ +#include <memory> + #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 f959e814bdf7fa569a0d5ab52f2f90615c038f07..1d5c3c7bdc855a835dea7a4b3dd42a013646351c 100644 --- a/src/ftxui/dom/bold.cpp +++ b/src/ftxui/dom/bold.cpp @@ -1,5 +1,10 @@ +#include <memory> + #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 2d1463772e742360e70efc8e92a21e54ceb857b1..a7ce81c5720d2356b9f1acaae41c8110abe64c2f 100644 --- a/src/ftxui/dom/border.cpp +++ b/src/ftxui/dom/border.cpp @@ -1,7 +1,14 @@ -#include <algorithm> - -#include "ftxui/dom/elements.hpp" -#include "ftxui/dom/node.hpp" +#include <algorithm> // for max +#include <iterator> // for begin, end +#include <memory> // for make_shared, __shared_ptr_access +#include <utility> // for move +#include <vector> // for vector + +#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 da0c60096a783edd12e4919c550b6b7649e9a232..23fb36cbe923be98535735cb48fe15e7d235b3ea 100644 --- a/src/ftxui/dom/clear_under.cpp +++ b/src/ftxui/dom/clear_under.cpp @@ -1,5 +1,10 @@ +#include <memory> + #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 023dc8f7a8488b2b78cb2f09fd22948ccb56ff6a..475d97865543deaecda23ab4f9a2841ad25f5e93 100644 --- a/src/ftxui/dom/color.cpp +++ b/src/ftxui/dom/color.cpp @@ -1,5 +1,10 @@ +#include <memory> + #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 c8183276218ed136eda50d9b2566d5cf6d1eeff6..007057ccfdeb7d90c83e90d7b0dc023502e8e8cb 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 ea737910302d904c9fa3d468373256b5ce2fe3be..e39283bd7fb1829885678f09a14d6eff83d03624 100644 --- a/src/ftxui/dom/dbox.cpp +++ b/src/ftxui/dom/dbox.cpp @@ -1,7 +1,12 @@ -#include <algorithm> - -#include "ftxui/dom/elements.hpp" -#include "ftxui/dom/node.hpp" +#include <algorithm> // for max +#include <memory> // for __shared_ptr_access, shared_ptr, make_shared +#include <utility> // for move +#include <vector> // for vector + +#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 7b6b68ad6cece50dede44507387b35a06adb4553..296ea1d79b55d8b90dda1acb2f6e0f633cf00dbb 100644 --- a/src/ftxui/dom/dim.cpp +++ b/src/ftxui/dom/dim.cpp @@ -1,5 +1,10 @@ +#include <memory> + #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 bf2942e6cb4cd8cb735092df60ed2079e68998de..303481c48adc79a7212ed964675ab271fb7e85f0 100644 --- a/src/ftxui/dom/flex.cpp +++ b/src/ftxui/dom/flex.cpp @@ -1,5 +1,10 @@ +#include <memory> +#include <vector> + #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 7e25c8c09e8cce8721f23f36d8c300cb04f80c29..05f3ea92726ead77998318491f38eea21a5f9a4f 100644 --- a/src/ftxui/dom/frame.cpp +++ b/src/ftxui/dom/frame.cpp @@ -1,8 +1,14 @@ -#include <algorithm> - -#include "ftxui/dom/elements.hpp" -#include "ftxui/dom/node.hpp" -#include "ftxui/util/autoreset.hpp" +#include <algorithm> // for max, min +#include <memory> // for make_shared, shared_ptr, __shared_ptr_access +#include <utility> // for move +#include <vector> // for vector + +#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 d448036a3c49afe72939d79589240a92efd48295..fe45c4b6a0bdeade8e7d5280d493c31cff00d178 100644 --- a/src/ftxui/dom/gauge.cpp +++ b/src/ftxui/dom/gauge.cpp @@ -1,5 +1,9 @@ +#include <memory> + #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 10563967268329f5d057d034dcb1e3036995309a..0eb3275e5acd85808748bad2f5b09b48ad1d19c8 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 <gtest/gtest-message.h> // for Message +#include <gtest/gtest-test-part.h> // for TestPartResult +#include <memory> // 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 67f0cd36a826c50b4564b816b08ebdeb78342b05..4261bdefc30989988cf5e42d8efbda507ff93d4d 100644 --- a/src/ftxui/dom/graph.cpp +++ b/src/ftxui/dom/graph.cpp @@ -1,4 +1,12 @@ -#include "ftxui/dom/elements.hpp" +#include <functional> // for function +#include <memory> // for make_shared +#include <vector> // 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 3ff91e008e327a2b0c05dd2305d396e86595e686..43757e6fae5a1acae0a33bef03f53772e37f44d5 100644 --- a/src/ftxui/dom/hbox.cpp +++ b/src/ftxui/dom/hbox.cpp @@ -1,7 +1,12 @@ -#include <algorithm> - -#include "ftxui/dom/elements.hpp" -#include "ftxui/dom/node.hpp" +#include <algorithm> // for max +#include <memory> // for __shared_ptr_access, shared_ptr, make_shared +#include <utility> // for move +#include <vector> // for vector + +#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 dbeac3a65b07187172c36226bc4dd6318d9a4f4a..fc5ca6c06d8c40a880d26bf932d6beb65bce44c0 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 <gtest/gtest-message.h> // for Message +#include <gtest/gtest-test-part.h> // for TestPartResult +#include <string> // for allocator, basic_string, string +#include <vector> // 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 ee6ff0470fd53ce9a873f5a0b4fef90cb3c3119a..eb20233c5769e56b0d1d307fceb6cba62f1f055a 100644 --- a/src/ftxui/dom/hflow.cpp +++ b/src/ftxui/dom/hflow.cpp @@ -1,7 +1,12 @@ -#include <algorithm> +#include <algorithm> // for max +#include <memory> // for __shared_ptr_access, make_shared, shared_ptr +#include <utility> // for move +#include <vector> // 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 10549909eb869cb3aa1f78007d42fa512679388b..c85954637bd194040f77301fb9e51543881d7180 100644 --- a/src/ftxui/dom/inverted.cpp +++ b/src/ftxui/dom/inverted.cpp @@ -1,5 +1,10 @@ +#include <memory> +#include <utility> + #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 d5f08c7d1dd3ac39c01563cd505332adeb96daba..9ed078b65687a0fcd1ec1ce78fd0510a82121c37 100644 --- a/src/ftxui/dom/node.cpp +++ b/src/ftxui/dom/node.cpp @@ -1,4 +1,7 @@ +#include <utility> + #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 db5c39a58a852723a009a3d3ee45d3a0a7c5c2ac..b98c2c2a93c0b0d1ff026a00227b0be55a9c0be3 100644 --- a/src/ftxui/dom/node_decorator.cpp +++ b/src/ftxui/dom/node_decorator.cpp @@ -1,4 +1,9 @@ +#include <memory> // for __shared_ptr_access +#include <vector> // 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 0336b04c823e3677fd80b2ca9510d87e3006efa1..a9f1d4f43f25c1bf9a29e58b8476531a7eeea904 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 <utility> // 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 7a8a8e7b2ca907e3bb89a47febf98fad2ad3e229..a90c18d7581e57146658c5360e244762f572e666 100644 --- a/src/ftxui/dom/paragraph.cpp +++ b/src/ftxui/dom/paragraph.cpp @@ -1,4 +1,5 @@ #include <sstream> +#include <string> #include "ftxui/dom/elements.hpp" diff --git a/src/ftxui/dom/reflect.cpp b/src/ftxui/dom/reflect.cpp new file mode 100644 index 0000000000000000000000000000000000000000..79998ad610d1bbac1832c70ccf73b6adf673db2d --- /dev/null +++ b/src/ftxui/dom/reflect.cpp @@ -0,0 +1,44 @@ +#include <memory> +#include <utility> +#include <vector> + +#include "ftxui/dom/elements.hpp" +#include "ftxui/dom/node.hpp" +#include "ftxui/dom/requirement.hpp" +#include "ftxui/screen/box.hpp" + +namespace ftxui { + +// 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<Reflect>(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/dom/separator.cpp b/src/ftxui/dom/separator.cpp index 0997d6e4a3d4884d34e0cfff9fabbfa74a6ac46d..243249dc334eb461fcd7328573980ca1cec31adf 100644 --- a/src/ftxui/dom/separator.cpp +++ b/src/ftxui/dom/separator.cpp @@ -1,5 +1,9 @@ +#include <memory> + #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 5bb4cb417fd24c3f3501fa192e475947db1e7856..f5621b68a8a5dc6ddc519b036eda9ecb039bf6dd 100644 --- a/src/ftxui/dom/size.cpp +++ b/src/ftxui/dom/size.cpp @@ -1,7 +1,13 @@ -#include <algorithm> +#include <stddef.h> // for size_t +#include <algorithm> // for min, max +#include <memory> // for make_shared, __shared_ptr_access +#include <utility> // for move +#include <vector> // 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 24ea38ba74f0adbd0d47124862d0e7a19a0c3508..e415acceb14bf5c84e473538c9cf4351d907be4c 100644 --- a/src/ftxui/dom/spinner.cpp +++ b/src/ftxui/dom/spinner.cpp @@ -1,5 +1,9 @@ +#include <stddef.h> +#include <memory> +#include <string> +#include <vector> + #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 0a30f7dd55a02759f39877876e9a0230c534ffed..a8ade9aee99430158fc4b0bc992d0fd367a5539b 100644 --- a/src/ftxui/dom/text.cpp +++ b/src/ftxui/dom/text.cpp @@ -1,7 +1,13 @@ -#include <algorithm> -#include "ftxui/dom/elements.hpp" -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/string.hpp" +#include <algorithm> // for max +#include <memory> // for make_shared +#include <string> // 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 34fe2a55ce1a6f5b23e5551acfca80dcd2c4a60a..a1a55518cd290261b72fd34b9012ec3c500e66c3 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 <gtest/gtest-message.h> // for Message +#include <gtest/gtest-test-part.h> // for TestPartResult +#include <memory> // 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 b04a1108e06323ad92584826a0a8740f53ef50e9..7a3a50f127465a5c864e18410150e8981efdae46 100644 --- a/src/ftxui/dom/underlined.cpp +++ b/src/ftxui/dom/underlined.cpp @@ -1,5 +1,10 @@ +#include <memory> +#include <utility> + #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 bc86b1b2ba64bb72a83f9df2dcb8fc2d841ebca7..1770611915ee03dbfc3c6ec55491cddbcbf0eb04 100644 --- a/src/ftxui/dom/util.cpp +++ b/src/ftxui/dom/util.cpp @@ -1,4 +1,7 @@ -#include "ftxui/dom/elements.hpp" +#include <functional> // for function +#include <utility> // 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 e514ae0c9943712d00e08b8bd2bdd9395ca4e446..0686498225bd9cb7dac62360274fedf814ecd2b7 100644 --- a/src/ftxui/dom/vbox.cpp +++ b/src/ftxui/dom/vbox.cpp @@ -1,8 +1,12 @@ -#include <algorithm> -#include <iostream> - -#include "ftxui/dom/elements.hpp" -#include "ftxui/dom/node.hpp" +#include <algorithm> // for max +#include <memory> // for __shared_ptr_access, shared_ptr, make_shared +#include <utility> // for move +#include <vector> // for vector + +#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 917afd9d7479ba5a30159ca65349c32ab5488989..19aa8b9c9f110b8f8b86c678097b778e84242d65 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 <gtest/gtest-message.h> // for Message +#include <gtest/gtest-test-part.h> // for TestPartResult +#include <algorithm> // for remove +#include <string> // for allocator, basic_string, string +#include <vector> // 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/box.cpp b/src/ftxui/screen/box.cpp index b8ed1ee89bdf8d1c9e0f2ff0bf65b1caf67dc235..07826f819a83a44162e338906a60bb7120b97c5b 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. diff --git a/src/ftxui/screen/color.cpp b/src/ftxui/screen/color.cpp index e71547ee8eb004ec52509e74d0442ac07fd61889..ca2a4597f7b3767df9711ad5720c269a4d449f2a 100644 --- a/src/ftxui/screen/color.cpp +++ b/src/ftxui/screen/color.cpp @@ -1,7 +1,4 @@ #include "ftxui/screen/color.hpp" - -#include <algorithm> - #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 2a12a2f655b88130abaf558498cbfbdc2dd6030c..a63001117577368e2079ea9f021fc7afb042390a 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 d83e42455daf1a96e114f274c7e31021b2a79d3f..5a3dbd195439873519dd5736ad5c507b1271f5b0 100644 --- a/src/ftxui/screen/screen.cpp +++ b/src/ftxui/screen/screen.cpp @@ -1,12 +1,12 @@ -#include "ftxui/screen/screen.hpp" - -#include <algorithm> -#include <sstream> -#include <iostream> +#include <algorithm> // for min +#include <iostream> // for operator<<, basic_ostream, wstringstream, stringstream, flush, cout, ostream +#include <sstream> // IWYU pragma: keep -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/string.hpp" -#include "ftxui/screen/terminal.hpp" +#include "ftxui/dom/node.hpp" // for Element, Node +#include "ftxui/dom/requirement.hpp" // for Requirement +#include "ftxui/screen/screen.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; @@ -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. diff --git a/src/ftxui/screen/terminal.cpp b/src/ftxui/screen/terminal.cpp index fea187e3d9ba52bc2c36ed27d45a41b427da67b0..213377f41d96c529435621b82dfbbfcbf5c4c0e1 100644 --- a/src/ftxui/screen/terminal.cpp +++ b/src/ftxui/screen/terminal.cpp @@ -1,8 +1,7 @@ -#include "ftxui/screen/terminal.hpp" - -#include <stdio.h> +#include <cstdlib> // for getenv +#include <string> // for string, allocator -#include <cstdlib> +#include "ftxui/screen/terminal.hpp" #if defined(_WIN32) #define WIN32_LEAN_AND_MEAN @@ -13,12 +12,10 @@ #include <Windows.h> #else -#include <sys/ioctl.h> -#include <unistd.h> +#include <sys/ioctl.h> // for winsize, ioctl, TIOCGWINSZ +#include <unistd.h> // for STDOUT_FILENO #endif -#include <iostream> - namespace ftxui { Terminal::Dimensions Terminal::Size() { diff --git a/src/ftxui/screen/wcwidth.cpp b/src/ftxui/screen/wcwidth.cpp index 6d3bcdbc7511ca9b6f30ea82e9806911f1aa2f01..7791a3e482bdda23d51e4fc2edb350825e369910 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 <wchar.h> +#include <string> #include "ftxui/screen/string.hpp" diff --git a/tools/iwyu.sh b/tools/iwyu.sh new file mode 100755 index 0000000000000000000000000000000000000000..1e1f62b10fe96924decf5bb6abb23b40b0c4422c --- /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