From b352e13253e220f1be711400337e24987e38a9b8 Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Sat, 31 Aug 2024 15:39:42 +0200 Subject: [PATCH] Reformat + fix pending selection. --- examples/component/selectable_input.cpp | 16 ++-- .../ftxui/component/screen_interactive.hpp | 13 +-- include/ftxui/dom/node.hpp | 6 ++ src/ftxui/component/screen_interactive.cpp | 95 ++++++++++++------- 4 files changed, 79 insertions(+), 51 deletions(-) diff --git a/examples/component/selectable_input.cpp b/examples/component/selectable_input.cpp index 807ef46a..91dd577c 100644 --- a/examples/component/selectable_input.cpp +++ b/examples/component/selectable_input.cpp @@ -1,10 +1,8 @@ // 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. -#include // for allocator, __shared_ptr_access #include // for char_traits, operator+, string, basic_string -#include "ftxui/component/captured_mouse.hpp" // for ftxui #include "ftxui/component/component.hpp" // for Input, Renderer, Vertical #include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_options.hpp" // for InputOption @@ -12,7 +10,6 @@ #include "ftxui/dom/elements.hpp" // for text, hbox, separator, Element, operator|, vbox, border #include "ftxui/util/ref.hpp" // for Ref - int main() { using namespace ftxui; @@ -38,10 +35,10 @@ int main() { // The phone number input component: // We are using `CatchEvent` to filter out non-digit characters. Component input_phone_number = Input(&phoneNumber, "phone number"); - input_phone_number |= CatchEvent([&](Event event) { + input_phone_number |= CatchEvent([&](const Event& event) { return event.is_character() && !std::isdigit(event.character()[0]); }); - input_phone_number |= CatchEvent([&](Event event) { + input_phone_number |= CatchEvent([&](const Event& event) { return event.is_character() && phoneNumber.size() > 10; }); @@ -55,17 +52,18 @@ int main() { // Tweak how the component tree is rendered: auto renderer = Renderer(component, [&] { - return vbox({ hbox(text(" First name : "), input_first_name->Render()), - hbox(text(" Last name : ") | selectable(), input_last_name->Render()), + hbox(text(" Last name : ") | selectable(), + input_last_name->Render()), hbox(text(" Password : "), input_password->Render()), - hbox(text(" Phone num : "), input_phone_number->Render()) | selectable(), + hbox(text(" Phone num : "), input_phone_number->Render()) | + selectable(), separator(), text("Hello " + first_name + " " + last_name), text("Your password is " + password), text("Your phone number is " + phoneNumber), - text("Selected test is " + screen.getSelection()) + text("Selected test is " + screen.GetSelection()), }) | border; }); diff --git a/include/ftxui/component/screen_interactive.hpp b/include/ftxui/component/screen_interactive.hpp index faf1e838..49f18377 100644 --- a/include/ftxui/component/screen_interactive.hpp +++ b/include/ftxui/component/screen_interactive.hpp @@ -27,7 +27,6 @@ using Component = std::shared_ptr; class ScreenInteractivePrivate; typedef struct { - uint16_t startx = 0; uint16_t endx = 0; uint16_t starty = 0; @@ -76,7 +75,7 @@ class ScreenInteractive : public Screen { void ForceHandleCtrlC(bool force); void ForceHandleCtrlZ(bool force); - std::string getSelection(void); + std::string GetSelection(); private: void ExitNow(); @@ -92,8 +91,8 @@ class ScreenInteractive : public Screen { void RunOnceBlocking(Component component); void HandleTask(Component component, Task& task); - bool selectableCatchEvent(Event event); - void refreshSelection(void); + bool HandleSelection(Event event); + void RefreshSelection(); void Draw(Component component); void ResetCursorPosition(); @@ -138,8 +137,10 @@ class ScreenInteractive : public Screen { bool force_handle_ctrl_c_ = true; bool force_handle_ctrl_z_ = true; - Region selectedRegion; - std::string selectedText; + bool selection_enabled = false; + CapturedMouse selection_pending; + Region selection_region; + std::string selection_text; // The style of the cursor to restore on exit. int cursor_reset_shape_ = 1; diff --git a/include/ftxui/dom/node.hpp b/include/ftxui/dom/node.hpp index f43157a9..5a71512e 100644 --- a/include/ftxui/dom/node.hpp +++ b/include/ftxui/dom/node.hpp @@ -52,6 +52,12 @@ class Node { }; virtual void Check(Status* status); + // Selection. + // Propagated from Parents to Children. + virtual void Select(Box selected_area) { + // TODO: Implement this. + } + protected: Elements children_; Requirement requirement_; diff --git a/src/ftxui/component/screen_interactive.cpp b/src/ftxui/component/screen_interactive.cpp index f9bc9398..998e5393 100644 --- a/src/ftxui/component/screen_interactive.cpp +++ b/src/ftxui/component/screen_interactive.cpp @@ -352,7 +352,7 @@ ScreenInteractive::ScreenInteractive(int dimx, : Screen(dimx, dimy), dimension_(dimension), use_alternative_screen_(use_alternative_screen), - selectedText("") { + selection_text("") { task_receiver_ = MakeReceiver(); } @@ -784,13 +784,7 @@ void ScreenInteractive::HandleTask(Component component, Task& task) { bool handled = component->OnEvent(arg); - if(handled == false) - { - if(selectableCatchEvent(arg)) - { - handled = true; - } - } + handled = handled || HandleSelection(arg); if (arg == Event::CtrlC && (!handled || force_handle_ctrl_c_)) { RecordSignal(SIGABRT); @@ -834,48 +828,77 @@ void ScreenInteractive::HandleTask(Component component, Task& task) { } // private -bool ScreenInteractive::selectableCatchEvent(Event event) { +bool ScreenInteractive::HandleSelection(Event event) { + if (!event.is_mouse()) { + return false; + } - if (event.is_mouse()) { - auto& mouse = event.mouse(); - if (mouse.button == Mouse::Left) { + auto& mouse = event.mouse(); + if (mouse.button != Mouse::Left) { + return false; + } - if (mouse.motion == Mouse::Pressed) { - selectedRegion.startx = mouse.x; - selectedRegion.starty = mouse.y; - selectedRegion.endx = mouse.x; - selectedRegion.endy = mouse.y; - } else if (mouse.motion == Mouse::Released) { - selectedRegion.endx = mouse.x; - selectedRegion.endy = mouse.y; - } else if (mouse.motion == Mouse::Moved) { - selectedRegion.endx = mouse.x; - selectedRegion.endy = mouse.y; - } + if (mouse.motion == Mouse::Pressed) { + selection_pending = CaptureMouse(); + if (!selection_pending) { + return false; } + selection_enabled = true; + selection_region.startx = mouse.x; + selection_region.starty = mouse.y; + selection_region.endx = mouse.x; + selection_region.endy = mouse.y; + return true; + } + + if (!selection_pending) { + return false; + } + + if (mouse.motion == Mouse::Moved) { + selection_region.endx = mouse.x; + selection_region.endy = mouse.y; + return true; + } + + if (mouse.motion == Mouse::Released) { + selection_region.endx = mouse.x; + selection_region.endy = mouse.y; + selection_pending = nullptr; + + if (selection_region.startx == selection_region.endx && + selection_region.starty == selection_region.endy) { + selection_enabled = false; + return true; + } + + return true; } return false; } -void ScreenInteractive::refreshSelection(void) { +void ScreenInteractive::RefreshSelection() { + if (!selection_enabled) { + return; + } + selection_text = ""; - selectedText = ""; - - for (int y = std::min(selectedRegion.starty, selectedRegion.endy); y <= std::max(selectedRegion.starty, selectedRegion.endy); ++y) { - for (int x = std::min(selectedRegion.startx, selectedRegion.endx); x <= std::max(selectedRegion.startx, selectedRegion.endx)-1; ++x) { - if(PixelAt(x, y).selectable == true) - { + for (int y = std::min(selection_region.starty, selection_region.endy); + y <= std::max(selection_region.starty, selection_region.endy); ++y) { + for (int x = std::min(selection_region.startx, selection_region.endx); + x <= std::max(selection_region.startx, selection_region.endx) - 1; + ++x) { + if (PixelAt(x, y).selectable == true) { PixelAt(x, y).inverted ^= true; - selectedText += PixelAt(x, y).character; + selection_text += PixelAt(x, y).character; } } } } -std::string ScreenInteractive::getSelection(void) { - - return selectedText; +std::string ScreenInteractive::GetSelection() { + return selection_text; } // private @@ -955,7 +978,7 @@ void ScreenInteractive::Draw(Component component) { Render(*this, document); - refreshSelection(); + RefreshSelection(); // Set cursor position for user using tools to insert CJK characters. {