From cbd28403af71ee73c9491b5a87a1539fbce84595 Mon Sep 17 00:00:00 2001 From: Clement Roblot Date: Mon, 2 Dec 2024 19:34:27 +0700 Subject: [PATCH] Added a option to set the style of the selection --- examples/component/selectable_input.cpp | 11 +++++--- .../ftxui/component/screen_interactive.hpp | 5 ++-- include/ftxui/dom/selection.hpp | 21 +++++++++++++++- src/ftxui/component/screen_interactive.cpp | 16 +++++------- src/ftxui/dom/selection.cpp | 25 ++++++++++++++++--- src/ftxui/dom/text.cpp | 5 +++- 6 files changed, 63 insertions(+), 20 deletions(-) diff --git a/examples/component/selectable_input.cpp b/examples/component/selectable_input.cpp index 36e22996..ac2d41fb 100644 --- a/examples/component/selectable_input.cpp +++ b/examples/component/selectable_input.cpp @@ -73,9 +73,14 @@ int main() { }); }); - screen.onSelectionModified([&] { - selectionChangeCounter++; - selection = screen.GetSelectedContent(renderer); + screen.setSelectionOptions({ + .transform = [](Pixel& pixel) { + pixel.underlined_double = true; + }, + .on_change = [&] { + selectionChangeCounter++; + selection = screen.GetSelectedContent(renderer); + } }); screen.Loop(renderer); diff --git a/include/ftxui/component/screen_interactive.hpp b/include/ftxui/component/screen_interactive.hpp index 3e09fe0d..14daf1f2 100644 --- a/include/ftxui/component/screen_interactive.hpp +++ b/include/ftxui/component/screen_interactive.hpp @@ -15,6 +15,7 @@ #include "ftxui/component/animation.hpp" // for TimePoint #include "ftxui/component/captured_mouse.hpp" // for CapturedMouse #include "ftxui/component/event.hpp" // for Event +#include "ftxui/dom/selection.hpp" // for SelectionOption #include "ftxui/component/task.hpp" // for Task, Closure #include "ftxui/screen/screen.hpp" // for Screen @@ -70,7 +71,7 @@ class ScreenInteractive : public Screen { // Selection API. std::string GetSelectedContent(Component component); - void onSelectionModified(std::function callback); + void setSelectionOptions(SelectionOption option); private: void ExitNow(); @@ -143,7 +144,7 @@ class ScreenInteractive : public Screen { int selection_end_x_ = 0; int selection_end_y_ = 0; bool selection_changed = false; - std::function selection_changed_callback_ = nullptr; + SelectionOption selection_options_ = SelectionOption::Simple(); friend class Loop; diff --git a/include/ftxui/dom/selection.hpp b/include/ftxui/dom/selection.hpp index 588e367d..16f90c1d 100644 --- a/include/ftxui/dom/selection.hpp +++ b/include/ftxui/dom/selection.hpp @@ -5,15 +5,33 @@ #ifndef FTXUI_DOM_SELECTION_HPP #define FTXUI_DOM_SELECTION_HPP +#include + #include "ftxui/screen/box.hpp" // for Box +#include "ftxui/screen/pixel.hpp" // for Pixel namespace ftxui { +/// @brief Option for the selection of content. +/// @ingroup component +struct SelectionOption { + /// @brief Selection is simply inverted: + static SelectionOption Simple(); + + // Style: + std::function transform ; + + // Observers: + /// Called when the selection changed. + std::function on_change = [] {}; +}; + /// @brief Represent a selection in the terminal. class Selection { public: - Selection(int start_x, int start_y, int end_x, int end_y); + Selection(int start_x, int start_y, int end_x, int end_y, SelectionOption option = SelectionOption::Simple()); const Box& GetBox() const; + const SelectionOption& GetOption() const; Selection SaturateHorizontal(Box box); Selection SaturateVertical(Box box); @@ -25,6 +43,7 @@ class Selection { const int end_x_; const int end_y_; const Box box_; + const SelectionOption option; }; } // namespace ftxui diff --git a/src/ftxui/component/screen_interactive.cpp b/src/ftxui/component/screen_interactive.cpp index caac62cb..ebc7d117 100644 --- a/src/ftxui/component/screen_interactive.cpp +++ b/src/ftxui/component/screen_interactive.cpp @@ -580,18 +580,14 @@ void ScreenInteractive::ForceHandleCtrlZ(bool force) { std::string ScreenInteractive::GetSelectedContent(Component component) { Selection selection(selection_start_x_, selection_start_y_, // - selection_end_x_, selection_end_y_); + selection_end_x_, selection_end_y_, selection_options_); return GetNodeSelectedContent(*this, component->Render().get(), selection); } -/// @brief Sets a callback on modifications of the selection -/// This callback is called when the start of end of the selection moved. -/// Not when the content/characters inside of the selection change. -/// @param callback The function to callback on modifications of the selection. -void ScreenInteractive::onSelectionModified(std::function callback) +void ScreenInteractive::setSelectionOptions(SelectionOption option) { - selection_changed_callback_ = std::move(callback); + selection_options_ = std::move(option); } /// @brief Return the currently active screen, or null if none. @@ -970,12 +966,12 @@ void ScreenInteractive::Draw(Component component) { previous_frame_resized_ = resized; Selection selection(selection_start_x_, selection_start_y_, // - selection_end_x_, selection_end_y_); + selection_end_x_, selection_end_y_, selection_options_); Render(*this, document.get(), selection); - if((selection_changed == true) && (selection_changed_callback_ != nullptr)) + if(selection_changed == true) { - selection_changed_callback_(); + selection_options_.on_change(); } // Set cursor position for user using tools to insert CJK characters. diff --git a/src/ftxui/dom/selection.cpp b/src/ftxui/dom/selection.cpp index 2e651d54..0bcccb25 100644 --- a/src/ftxui/dom/selection.cpp +++ b/src/ftxui/dom/selection.cpp @@ -26,11 +26,12 @@ class Unselectable : public NodeDecorator { /// @param start_y The y coordinate of the start of the selection. /// @param end_x The x coordinate of the end of the selection. /// @param end_y The y coordinate of the end of the selection. -Selection::Selection(int start_x, int start_y, int end_x, int end_y) +Selection::Selection(int start_x, int start_y, int end_x, int end_y, SelectionOption option) : start_x_(start_x), start_y_(start_y), end_x_(end_x), end_y_(end_y), + option(option), box_{ std::min(start_x, end_x), std::max(start_x, end_x), @@ -44,6 +45,12 @@ const Box& Selection::GetBox() const { return box_; } +/// @brief Get the options of the selection. +/// @return The options of the selection. +const SelectionOption& Selection::GetOption() const { + return option; +} + /// @brief Saturate the selection to be inside the box. /// This is called by `hbox` to propagate the selection to its children. /// @param box The box to saturate the selection in. @@ -77,7 +84,7 @@ Selection Selection::SaturateHorizontal(Box box) { end_y = box.y_min; } } - return Selection(start_x, start_y, end_x, end_y); + return Selection(start_x, start_y, end_x, end_y, option); } /// @brief Saturate the selection to be inside the box. @@ -114,7 +121,7 @@ Selection Selection::SaturateVertical(Box box) { end_y = box.y_min; } } - return Selection(start_x, start_y, end_x, end_y); + return Selection(start_x, start_y, end_x, end_y, option); } /// @brief Add a filter that will invert the foreground and the background @@ -124,4 +131,16 @@ Element unselectable(Element child) { return std::make_shared(std::move(child)); } +/// @brief Create a SelectionOption, inverting the selection. +/// @ingroup component +// static +SelectionOption SelectionOption::Simple() { + SelectionOption option; + option.transform = [](Pixel& pixel) { + + pixel.inverted = true; + }; + return option; +} + } // namespace ftxui diff --git a/src/ftxui/dom/text.cpp b/src/ftxui/dom/text.cpp index f2b70903..c7bfbc56 100644 --- a/src/ftxui/dom/text.cpp +++ b/src/ftxui/dom/text.cpp @@ -39,6 +39,8 @@ class Text : public Node { has_selection = true; selection_start_ = selection_saturated.GetBox().x_min; selection_end_ = selection_saturated.GetBox().x_max; + + selectionTransform = selection.GetOption().transform; } void Render(Screen& screen) override { @@ -60,7 +62,7 @@ class Text : public Node { if (has_selection) { if ((x >= selection_start_) && (x <= selection_end_)) { - screen.PixelAt(x, y).inverted = true; + selectionTransform(screen.PixelAt(x, y)); } } @@ -96,6 +98,7 @@ class Text : public Node { bool has_selection = false; int selection_start_ = 0; int selection_end_ = 10; + std::function selectionTransform; }; class VText : public Node {