From 2de925f2c6141ed7213242e7cf5fce9851a0cd4e Mon Sep 17 00:00:00 2001 From: Clement Roblot Date: Fri, 2 Aug 2024 23:03:37 +0700 Subject: [PATCH] Better integratiion --- CMakeLists.txt | 2 +- examples/component/input.cpp | 42 ++---------------- include/ftxui/dom/elements.hpp | 6 ++- src/ftxui/dom/selectable.cpp | 80 ++++++++++++++++++++++++++++++++++ src/ftxui/dom/selected.cpp | 53 ---------------------- 5 files changed, 89 insertions(+), 94 deletions(-) create mode 100644 src/ftxui/dom/selectable.cpp delete mode 100644 src/ftxui/dom/selected.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 350278ef..24446574 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,7 +82,7 @@ add_library(dom src/ftxui/dom/gridbox.cpp src/ftxui/dom/hbox.cpp src/ftxui/dom/inverted.cpp - src/ftxui/dom/selected.cpp + src/ftxui/dom/selectable.cpp src/ftxui/dom/linear_gradient.cpp src/ftxui/dom/node.cpp src/ftxui/dom/node_decorator.cpp diff --git a/examples/component/input.cpp b/examples/component/input.cpp index b83a73a8..23962ce5 100644 --- a/examples/component/input.cpp +++ b/examples/component/input.cpp @@ -68,52 +68,18 @@ int main() { text("select_end " + std::to_string(selection.endx) + ";" + std::to_string(selection.endy)), text("textToCopy " + textToCopy) }) | - border | selected(selection, [&textToCopy](std::string selected){textToCopy = selected;}); + border | selectable([&textToCopy](std::string txtSelected){textToCopy = txtSelected;}); }); - // TODO: Is there a way for me to embedd the catchEvent in the selected decorator? At a minimum move the function in the selected.cpp file and add doc to call it // TODO: Implement the double click on word to select the word // TODO: Implement the double click and drag to select word by word (optional) + // TODO: Implement the tripple click to select an entire line + // TODO: Call onSelectionChange_ only when the selection indeed did change, not at every render? // TODO: Add a "selectable" flag in the pixel class and take it into account when selecting things renderer |= CatchEvent([&](Event event) { - if (event.is_mouse()) { - auto& mouse = event.mouse(); - if (mouse.button == Mouse::Left) { - if (mouse.motion == Mouse::Pressed) - { - selection.startx = mouse.x; - selection.starty = mouse.y; - selection.endx = mouse.x; - selection.endy = mouse.y; - } - else if (mouse.motion == Mouse::Released) - { - selection.endx = mouse.x; - selection.endy = mouse.y; - } - else if (mouse.motion == Mouse::Moved) - { - selection.endx = mouse.x; - selection.endy = mouse.y; - } - - screen.PostEvent(Event::Custom); - return true; - } - } - - // if (event == Event::SpecialKey("Ctrl+Shift+C")) { - // textToCopy = "Kikoo!"; - // //clip::set_text(text_to_copy); // Set the clipboard content - - // screen.PostEvent(Event::Custom); - - // return true; - // } - - return false; + return selectableCatchEvent(event); }); screen.Loop(renderer); diff --git a/include/ftxui/dom/elements.hpp b/include/ftxui/dom/elements.hpp index 3f4db35f..4579c8a8 100644 --- a/include/ftxui/dom/elements.hpp +++ b/include/ftxui/dom/elements.hpp @@ -16,6 +16,7 @@ #include "ftxui/screen/color.hpp" #include "ftxui/screen/terminal.hpp" #include "ftxui/util/ref.hpp" +#include "ftxui/component/event.hpp" namespace ftxui { class Node; @@ -104,8 +105,9 @@ Element canvas(std::function); Element bold(Element); Element dim(Element); Element inverted(Element); -Element selected(Region &selection, std::function onSelectionChange, Element); -Decorator selected(Region &selection, std::function onSelectionChange); +Element selectable(std::function onSelectionChange, Element); +Decorator selectable(std::function onSelectionChange); +bool selectableCatchEvent(Event event); Element underlined(Element); Element underlinedDouble(Element); Element blink(Element); diff --git a/src/ftxui/dom/selectable.cpp b/src/ftxui/dom/selectable.cpp new file mode 100644 index 00000000..f88a0274 --- /dev/null +++ b/src/ftxui/dom/selectable.cpp @@ -0,0 +1,80 @@ +// 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 make_shared +#include // for move + +#include "ftxui/dom/elements.hpp" // for Element, inverted +#include "ftxui/dom/node.hpp" // for Node +#include "ftxui/dom/node_decorator.hpp" // for NodeDecorator +#include "ftxui/screen/box.hpp" // for Box +#include "ftxui/screen/screen.hpp" // for Pixel, Screen + +namespace ftxui { + +Region newSelection; + +namespace { +class Selectable : public NodeDecorator { + public: + using NodeDecorator::NodeDecorator; + Selectable(Element child, std::function onSelectionChange) + : NodeDecorator(std::move(child)), onSelectionChange_(onSelectionChange) {} + + void Render(Screen& screen) override { + Node::Render(screen); + std::string selectedText = ""; + for (int y = std::min(newSelection.starty, newSelection.endy); y <= std::max(newSelection.starty, newSelection.endy); ++y) { + for (int x = std::min(newSelection.startx, newSelection.endx); x <= std::max(newSelection.startx, newSelection.endx)-1; ++x) { + screen.PixelAt(x, y).inverted ^= true; + selectedText += screen.PixelAt(x, y).character; + } + } + + onSelectionChange_(selectedText); + } + +private: + std::function onSelectionChange_; +}; +} // namespace + +/// @brief Add a filter that will invert the foreground and the background +/// colors. +/// @ingroup dom + +Element selectable(std::function onSelectionChange, Element child) { + return std::make_shared(std::move(child), onSelectionChange); +} + +Decorator selectable(std::function onSelectionChange) { + return [onSelectionChange](Element child) { return selectable(onSelectionChange, std::move(child)); }; +} + +bool selectableCatchEvent(Event event) { + + if (event.is_mouse()) { + auto& mouse = event.mouse(); + if (mouse.button == Mouse::Left) { + + if (mouse.motion == Mouse::Pressed) { + newSelection.startx = mouse.x; + newSelection.starty = mouse.y; + newSelection.endx = mouse.x; + newSelection.endy = mouse.y; + } else if (mouse.motion == Mouse::Released) { + newSelection.endx = mouse.x; + newSelection.endy = mouse.y; + } else if (mouse.motion == Mouse::Moved) { + newSelection.endx = mouse.x; + newSelection.endy = mouse.y; + } + + return true; + } + } + + return false; +} + +} // namespace ftxui diff --git a/src/ftxui/dom/selected.cpp b/src/ftxui/dom/selected.cpp deleted file mode 100644 index 701b6885..00000000 --- a/src/ftxui/dom/selected.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// 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 make_shared -#include // for move - -#include "ftxui/dom/elements.hpp" // for Element, inverted -#include "ftxui/dom/node.hpp" // for Node -#include "ftxui/dom/node_decorator.hpp" // for NodeDecorator -#include "ftxui/screen/box.hpp" // for Box -#include "ftxui/screen/screen.hpp" // for Pixel, Screen - -namespace ftxui { - -namespace { -class Selected : public NodeDecorator { - public: - using NodeDecorator::NodeDecorator; - Selected(Element child, Region &selection, std::function onSelectionChange) - : NodeDecorator(std::move(child)), selection_(selection), onSelectionChange_(onSelectionChange) {} - - void Render(Screen& screen) override { - Node::Render(screen); - std::string selectedText = ""; - for (int y = std::min(selection_.starty, selection_.endy); y <= std::max(selection_.starty, selection_.endy); ++y) { - for (int x = std::min(selection_.startx, selection_.endx); x <= std::max(selection_.startx, selection_.endx)-1; ++x) { - screen.PixelAt(x, y).inverted ^= true; - selectedText += screen.PixelAt(x, y).character; - } - } - - onSelectionChange_(selectedText); - } - -private: - Region &selection_; - std::function onSelectionChange_; -}; -} // namespace - -/// @brief Add a filter that will invert the foreground and the background -/// colors. -/// @ingroup dom - -Element selected(Region &selection, std::function onSelectionChange, Element child) { - return std::make_shared(std::move(child), selection, onSelectionChange); -} - -Decorator selected(Region &selection, std::function onSelectionChange) { - return [&selection, onSelectionChange](Element child) { return selected(selection, onSelectionChange, std::move(child)); }; -} - -} // namespace ftxui