Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Selection2 the come back #926

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ add_library(dom
src/ftxui/dom/paragraph.cpp
src/ftxui/dom/reflect.cpp
src/ftxui/dom/scroll_indicator.cpp
src/ftxui/dom/selectable.cpp
src/ftxui/dom/separator.cpp
src/ftxui/dom/size.cpp
src/ftxui/dom/spinner.cpp
Expand Down
1 change: 1 addition & 0 deletions examples/component/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ example(radiobox)
example(radiobox_in_frame)
example(renderer)
example(resizable_split)
example(selectable_input)
example(scrollbar)
example(slider)
example(slider_direction)
Expand Down
72 changes: 72 additions & 0 deletions examples/component/selectable_input.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// 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 <string> // for char_traits, operator+, string, basic_string

#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
#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
#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;

// The data:
std::string first_name;
std::string last_name;
std::string password;
std::string phoneNumber;
// Region selection;
std::string textToCopy;

auto screen = ScreenInteractive::TerminalOutput();

// The basic input components:
Component input_first_name = Input(&first_name, "first name");
Component input_last_name = Input(&last_name, "last name");

// The password input component:
InputOption password_option;
password_option.password = true;
Component input_password = Input(&password, "password", password_option);

// 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([&](const Event& event) {
return event.is_character() && !std::isdigit(event.character()[0]);
});
input_phone_number |= CatchEvent([&](const Event& event) {
return event.is_character() && phoneNumber.size() > 10;
});

// The component tree:
auto component = Container::Vertical({
input_first_name,
input_last_name,
input_password,
input_phone_number,
});

// 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(" Password : "), input_password->Render()),
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()),
}) |
border;
});

screen.Loop(renderer);
}
16 changes: 16 additions & 0 deletions include/ftxui/component/screen_interactive.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@
using Component = std::shared_ptr<ComponentBase>;
class ScreenInteractivePrivate;

typedef struct {

Check failure on line 29 in include/ftxui/component/screen_interactive.hpp

View workflow job for this annotation

GitHub Actions / Tests (Windows MSVC, windows-latest, cl)

unnamed class used in typedef name cannot declare members other than non-static data members, member enumerations, or member classes [D:\a\FTXUI\FTXUI\build\ftxui-tests.vcxproj]

Check failure on line 29 in include/ftxui/component/screen_interactive.hpp

View workflow job for this annotation

GitHub Actions / Tests (Windows MSVC, windows-latest, cl)

unnamed class used in typedef name cannot declare members other than non-static data members, member enumerations, or member classes [D:\a\FTXUI\FTXUI\build\examples\component\ftxui_example_button.vcxproj]

Check failure on line 29 in include/ftxui/component/screen_interactive.hpp

View workflow job for this annotation

GitHub Actions / Tests (Windows MSVC, windows-latest, cl)

unnamed class used in typedef name cannot declare members other than non-static data members, member enumerations, or member classes [D:\a\FTXUI\FTXUI\build\examples\component\ftxui_example_button_animated.vcxproj]

Check failure on line 29 in include/ftxui/component/screen_interactive.hpp

View workflow job for this annotation

GitHub Actions / Tests (Windows MSVC, windows-latest, cl)

unnamed class used in typedef name cannot declare members other than non-static data members, member enumerations, or member classes [D:\a\FTXUI\FTXUI\build\examples\component\ftxui_example_button_in_frame.vcxproj]

Check failure on line 29 in include/ftxui/component/screen_interactive.hpp

View workflow job for this annotation

GitHub Actions / Tests (Windows MSVC, windows-latest, cl)

unnamed class used in typedef name cannot declare members other than non-static data members, member enumerations, or member classes [D:\a\FTXUI\FTXUI\build\examples\component\ftxui_example_button_style.vcxproj]

Check failure on line 29 in include/ftxui/component/screen_interactive.hpp

View workflow job for this annotation

GitHub Actions / Tests (Windows MSVC, windows-latest, cl)

unnamed class used in typedef name cannot declare members other than non-static data members, member enumerations, or member classes [D:\a\FTXUI\FTXUI\build\examples\component\ftxui_example_canvas_animated.vcxproj]

Check failure on line 29 in include/ftxui/component/screen_interactive.hpp

View workflow job for this annotation

GitHub Actions / Tests (Windows MSVC, windows-latest, cl)

unnamed class used in typedef name cannot declare members other than non-static data members, member enumerations, or member classes [D:\a\FTXUI\FTXUI\build\examples\component\ftxui_example_checkbox.vcxproj]

Check failure on line 29 in include/ftxui/component/screen_interactive.hpp

View workflow job for this annotation

GitHub Actions / Tests (Windows MSVC, windows-latest, cl)

unnamed class used in typedef name cannot declare members other than non-static data members, member enumerations, or member classes [D:\a\FTXUI\FTXUI\build\examples\component\ftxui_example_checkbox_in_frame.vcxproj]

Check failure on line 29 in include/ftxui/component/screen_interactive.hpp

View workflow job for this annotation

GitHub Actions / Tests (Windows MSVC, windows-latest, cl)

unnamed class used in typedef name cannot declare members other than non-static data members, member enumerations, or member classes [D:\a\FTXUI\FTXUI\build\examples\component\ftxui_example_collapsible.vcxproj]

Check failure on line 29 in include/ftxui/component/screen_interactive.hpp

View workflow job for this annotation

GitHub Actions / Tests (Windows MSVC, windows-latest, cl)

unnamed class used in typedef name cannot declare members other than non-static data members, member enumerations, or member classes [D:\a\FTXUI\FTXUI\build\examples\component\ftxui_example_composition.vcxproj]
uint16_t startx = 0;
uint16_t endx = 0;
uint16_t starty = 0;
uint16_t endy = 0;
} Region;

class ScreenInteractive : public Screen {
public:
// Constructors:
Expand Down Expand Up @@ -68,6 +75,8 @@
void ForceHandleCtrlC(bool force);
void ForceHandleCtrlZ(bool force);

std::string GetSelection();

private:
void ExitNow();

Expand All @@ -82,6 +91,8 @@
void RunOnceBlocking(Component component);

void HandleTask(Component component, Task& task);
bool HandleSelection(Event event);
void RefreshSelection();
void Draw(Component component);
void ResetCursorPosition();

Expand Down Expand Up @@ -126,6 +137,11 @@
bool force_handle_ctrl_c_ = true;
bool force_handle_ctrl_z_ = true;

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;

Expand Down
2 changes: 2 additions & 0 deletions include/ftxui/dom/elements.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ Decorator focusPositionRelative(float x, float y);
Element automerge(Element child);
Decorator hyperlink(std::string link);
Element hyperlink(std::string link, Element child);
Element selectable(Element child);
Decorator selectable(void);

// --- Layout is
// Horizontal, Vertical or stacked set of elements.
Expand Down
6 changes: 6 additions & 0 deletions include/ftxui/dom/node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
Expand Down
2 changes: 2 additions & 0 deletions include/ftxui/screen/pixel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@
/// @brief A Unicode character and its associated style.
/// @ingroup screen
struct Pixel {
Pixel()

Check failure on line 16 in include/ftxui/screen/pixel.hpp

View workflow job for this annotation

GitHub Actions / Tests (Linux GCC, ubuntu-latest, gcc, gcov)

when initialized here [-Werror=reorder]
: blink(false),
bold(false),
dim(false),
inverted(false),
underlined(false),
underlined_double(false),
strikethrough(false),

Check failure on line 23 in include/ftxui/screen/pixel.hpp

View workflow job for this annotation

GitHub Actions / Tests (Linux Clang, ubuntu-latest, llvm, llvm-cov gcov)

field 'strikethrough' will be initialized after field 'selectable' [-Werror,-Wreorder-ctor]
selectable(false),
automerge(false) {}

// A bit field representing the style:
Expand All @@ -30,7 +31,8 @@
bool inverted : 1;
bool underlined : 1;
bool underlined_double : 1;
bool selectable : 1;

Check failure on line 34 in include/ftxui/screen/pixel.hpp

View workflow job for this annotation

GitHub Actions / Tests (Linux GCC, ubuntu-latest, gcc, gcov)

‘bool ftxui::Pixel::selectable’ [-Werror=reorder]
bool strikethrough : 1;

Check failure on line 35 in include/ftxui/screen/pixel.hpp

View workflow job for this annotation

GitHub Actions / Tests (Linux GCC, ubuntu-latest, gcc, gcov)

‘ftxui::Pixel::strikethrough’ will be initialized after [-Werror=reorder]
bool automerge : 1;

// The hyperlink associated with the pixel.
Expand Down
83 changes: 81 additions & 2 deletions src/ftxui/component/screen_interactive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,8 @@ ScreenInteractive::ScreenInteractive(int dimx,
bool use_alternative_screen)
: Screen(dimx, dimy),
dimension_(dimension),
use_alternative_screen_(use_alternative_screen) {
use_alternative_screen_(use_alternative_screen),
selection_text("") {
task_receiver_ = MakeReceiver<Task>();
}

Expand Down Expand Up @@ -781,7 +782,9 @@ void ScreenInteractive::HandleTask(Component component, Task& task) {

arg.screen_ = this;

const bool handled = component->OnEvent(arg);
bool handled = component->OnEvent(arg);

handled = handled || HandleSelection(arg);

if (arg == Event::CtrlC && (!handled || force_handle_ctrl_c_)) {
RecordSignal(SIGABRT);
Expand Down Expand Up @@ -824,6 +827,80 @@ void ScreenInteractive::HandleTask(Component component, Task& task) {
// clang-format on
}

// private
bool ScreenInteractive::HandleSelection(Event event) {
if (!event.is_mouse()) {
return false;
}

auto& mouse = event.mouse();
if (mouse.button != Mouse::Left) {
return false;
}

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() {
if (!selection_enabled) {
return;
}
selection_text = "";

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;
selection_text += PixelAt(x, y).character;
}
}
}
}

std::string ScreenInteractive::GetSelection() {
return selection_text;
}

// private
// NOLINTNEXTLINE
void ScreenInteractive::Draw(Component component) {
Expand Down Expand Up @@ -894,6 +971,8 @@ void ScreenInteractive::Draw(Component component) {

Render(*this, document);

RefreshSelection();

// Set cursor position for user using tools to insert CJK characters.
{
const int dx = dimx_ - 1 - cursor_.x + int(dimx_ != terminal.dimx);
Expand Down
39 changes: 39 additions & 0 deletions src/ftxui/dom/selectable.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include "ftxui/dom/elements.hpp" // for Element, Decorator
#include "ftxui/dom/node_decorator.hpp" // for NodeDecorator
#include "ftxui/component/event.hpp" // for Event


namespace ftxui {
namespace {

class Selectable : public NodeDecorator {
public:
explicit Selectable(Element child)
: NodeDecorator(std::move(child)) {}

private:
void Render(Screen& screen) override {

for (int y = box_.y_min; y <= box_.y_max; ++y) {
for (int x = box_.x_min; x <= box_.x_max; ++x) {
screen.PixelAt(x, y).selectable = true;
}
}

NodeDecorator::Render(screen);
}
};

} // namespace


Element selectable(Element child) {
return std::make_shared<Selectable>(std::move(child));
}

Decorator selectable(void) {
return
[](Element child) { return selectable(std::move(child)); };
}

} // namespace ftxui
Loading