mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2025-06-25 17:11:13 +08:00
Add recursive selection style.
This commit is contained in:
parent
d755ab31f1
commit
9f9effa683
@ -59,6 +59,7 @@ add_library(dom
|
|||||||
include/ftxui/dom/selection.hpp
|
include/ftxui/dom/selection.hpp
|
||||||
include/ftxui/dom/take_any_args.hpp
|
include/ftxui/dom/take_any_args.hpp
|
||||||
src/ftxui/dom/automerge.cpp
|
src/ftxui/dom/automerge.cpp
|
||||||
|
src/ftxui/dom/selection_style.cpp
|
||||||
src/ftxui/dom/blink.cpp
|
src/ftxui/dom/blink.cpp
|
||||||
src/ftxui/dom/bold.cpp
|
src/ftxui/dom/bold.cpp
|
||||||
src/ftxui/dom/border.cpp
|
src/ftxui/dom/border.cpp
|
||||||
|
@ -38,7 +38,7 @@ example(radiobox)
|
|||||||
example(radiobox_in_frame)
|
example(radiobox_in_frame)
|
||||||
example(renderer)
|
example(renderer)
|
||||||
example(resizable_split)
|
example(resizable_split)
|
||||||
example(selectable_input)
|
example(selection)
|
||||||
example(scrollbar)
|
example(scrollbar)
|
||||||
example(slider)
|
example(slider)
|
||||||
example(slider_direction)
|
example(slider_direction)
|
||||||
|
@ -1,87 +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 <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
|
|
||||||
|
|
||||||
using namespace ftxui;
|
|
||||||
|
|
||||||
Element LoremIpsum() {
|
|
||||||
return vbox({
|
|
||||||
text("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do "
|
|
||||||
"eiusmod tempor incididunt ut labore et dolore magna aliqua."),
|
|
||||||
text("Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris "
|
|
||||||
"nisi ut aliquip ex ea commodo consequat."),
|
|
||||||
text("Duis aute irure dolor in reprehenderit in voluptate velit esse "
|
|
||||||
"cillum dolore eu fugiat nulla pariatur."),
|
|
||||||
text("Excepteur sint occaecat cupidatat non proident, sunt in culpa qui "
|
|
||||||
"officia deserunt mollit anim id est laborum."),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
auto screen = ScreenInteractive::TerminalOutput();
|
|
||||||
int selectionChangeCounter = 0;
|
|
||||||
std::string selection = "";
|
|
||||||
|
|
||||||
auto quit = Button("Quit", screen.ExitLoopClosure());
|
|
||||||
|
|
||||||
// The components:
|
|
||||||
auto renderer = Renderer(quit, [&] {
|
|
||||||
return vbox({
|
|
||||||
text("Select changed: " + std::to_string(selectionChangeCounter) + " times"),
|
|
||||||
text("Currently selected: " + selection),
|
|
||||||
window(text("Horizontal split"), hbox({
|
|
||||||
LoremIpsum(),
|
|
||||||
separator(),
|
|
||||||
LoremIpsum(),
|
|
||||||
separator(),
|
|
||||||
LoremIpsum(),
|
|
||||||
})),
|
|
||||||
window(text("Vertical split"), vbox({
|
|
||||||
LoremIpsum(),
|
|
||||||
separator(),
|
|
||||||
LoremIpsum() | unselectable,
|
|
||||||
separator(),
|
|
||||||
LoremIpsum(),
|
|
||||||
})),
|
|
||||||
window(text("Vertical split"),
|
|
||||||
vbox({
|
|
||||||
window(text("horizontal split"), hbox({
|
|
||||||
LoremIpsum(),
|
|
||||||
separator(),
|
|
||||||
LoremIpsum(),
|
|
||||||
separator(),
|
|
||||||
LoremIpsum(),
|
|
||||||
})),
|
|
||||||
separator(),
|
|
||||||
window(text("horizontal split"), hbox({
|
|
||||||
LoremIpsum(),
|
|
||||||
separator(),
|
|
||||||
LoremIpsum(),
|
|
||||||
separator(),
|
|
||||||
LoremIpsum(),
|
|
||||||
})),
|
|
||||||
})),
|
|
||||||
quit->Render(),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
screen.setSelectionOptions({
|
|
||||||
.transform = [](Pixel& pixel) {
|
|
||||||
pixel.underlined_double = true;
|
|
||||||
},
|
|
||||||
.on_change = [&] {
|
|
||||||
selectionChangeCounter++;
|
|
||||||
selection = screen.GetSelectedContent(renderer);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
screen.Loop(renderer);
|
|
||||||
}
|
|
@ -71,7 +71,6 @@ class ScreenInteractive : public Screen {
|
|||||||
|
|
||||||
// Selection API.
|
// Selection API.
|
||||||
std::string GetSelectedContent(Component component);
|
std::string GetSelectedContent(Component component);
|
||||||
void setSelectionOptions(SelectionOption option);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ExitNow();
|
void ExitNow();
|
||||||
@ -137,14 +136,12 @@ class ScreenInteractive : public Screen {
|
|||||||
int cursor_reset_shape_ = 1;
|
int cursor_reset_shape_ = 1;
|
||||||
|
|
||||||
// Selection API:
|
// Selection API:
|
||||||
bool selection_enabled_ = false;
|
|
||||||
CapturedMouse selection_pending_;
|
CapturedMouse selection_pending_;
|
||||||
int selection_start_x_ = 0;
|
int selection_start_x_ = 0;
|
||||||
int selection_start_y_ = 0;
|
int selection_start_y_ = 0;
|
||||||
int selection_end_x_ = 0;
|
int selection_end_x_ = 0;
|
||||||
int selection_end_y_ = 0;
|
int selection_end_y_ = 0;
|
||||||
bool selection_changed = false;
|
bool selection_changed = false;
|
||||||
SelectionOption selection_options_ = SelectionOption::Simple();
|
|
||||||
|
|
||||||
friend class Loop;
|
friend class Loop;
|
||||||
|
|
||||||
|
@ -113,7 +113,11 @@ Decorator focusPositionRelative(float x, float y);
|
|||||||
Element automerge(Element child);
|
Element automerge(Element child);
|
||||||
Decorator hyperlink(std::string link);
|
Decorator hyperlink(std::string link);
|
||||||
Element hyperlink(std::string link, Element child);
|
Element hyperlink(std::string link, Element child);
|
||||||
Element unselectable(Element child);
|
Element selectionStyleReset(Element);
|
||||||
|
Decorator selectionColor(Color foreground);
|
||||||
|
Decorator selectionBackgroundColor(Color foreground);
|
||||||
|
Decorator selectionForegroundColor(Color foreground);
|
||||||
|
Decorator selectionStyle(std::function<void(Pixel&)> style);
|
||||||
|
|
||||||
// --- Layout is
|
// --- Layout is
|
||||||
// Horizontal, Vertical or stacked set of elements.
|
// Horizontal, Vertical or stacked set of elements.
|
||||||
|
@ -7,34 +7,16 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#include "ftxui/screen/box.hpp" // for Box
|
#include "ftxui/screen/box.hpp" // for Box
|
||||||
#include "ftxui/screen/pixel.hpp" // for Pixel
|
#include "ftxui/screen/pixel.hpp" // for Pixel
|
||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
|
|
||||||
/// @brief Option for the selection of content.
|
|
||||||
/// @ingroup component
|
|
||||||
struct SelectionOption {
|
|
||||||
/// @brief Selection is simply inverted:
|
|
||||||
static SelectionOption Simple();
|
|
||||||
|
|
||||||
// Style:
|
|
||||||
std::function<void(Pixel& pixel)> transform = [](Pixel& pixel) {
|
|
||||||
|
|
||||||
pixel.inverted = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Observers:
|
|
||||||
/// Called when the selection changed.
|
|
||||||
std::function<void()> on_change = [] {};
|
|
||||||
};
|
|
||||||
|
|
||||||
/// @brief Represent a selection in the terminal.
|
/// @brief Represent a selection in the terminal.
|
||||||
class Selection {
|
class Selection {
|
||||||
public:
|
public:
|
||||||
Selection(int start_x, int start_y, int end_x, int end_y, SelectionOption option = SelectionOption::Simple());
|
Selection(int start_x, int start_y, int end_x, int end_y);
|
||||||
const Box& GetBox() const;
|
const Box& GetBox() const;
|
||||||
const SelectionOption& GetOption() const;
|
|
||||||
|
|
||||||
Selection SaturateHorizontal(Box box);
|
Selection SaturateHorizontal(Box box);
|
||||||
Selection SaturateVertical(Box box);
|
Selection SaturateVertical(Box box);
|
||||||
@ -46,7 +28,6 @@ class Selection {
|
|||||||
const int end_x_;
|
const int end_x_;
|
||||||
const int end_y_;
|
const int end_y_;
|
||||||
const Box box_;
|
const Box box_;
|
||||||
const SelectionOption option;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ftxui
|
} // namespace ftxui
|
||||||
|
@ -4,12 +4,14 @@
|
|||||||
#ifndef FTXUI_SCREEN_SCREEN_HPP
|
#ifndef FTXUI_SCREEN_SCREEN_HPP
|
||||||
#define FTXUI_SCREEN_SCREEN_HPP
|
#define FTXUI_SCREEN_SCREEN_HPP
|
||||||
|
|
||||||
#include <cstdint> // for uint8_t
|
#include <cstdint> // for uint8_t
|
||||||
#include <string> // for string, basic_string, allocator
|
#include <functional> // for function
|
||||||
#include <vector> // for vector
|
#include <string> // for string, basic_string, allocator
|
||||||
|
#include <vector> // for vector
|
||||||
|
|
||||||
#include "ftxui/screen/image.hpp" // for Pixel, Image
|
#include "ftxui/screen/image.hpp" // for Pixel, Image
|
||||||
#include "ftxui/screen/terminal.hpp" // for Dimensions
|
#include "ftxui/screen/terminal.hpp" // for Dimensions
|
||||||
|
#include "ftxui/util/autoreset.hpp" // for AutoReset
|
||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
|
|
||||||
@ -67,9 +69,18 @@ class Screen : public Image {
|
|||||||
uint8_t RegisterHyperlink(const std::string& link);
|
uint8_t RegisterHyperlink(const std::string& link);
|
||||||
const std::string& Hyperlink(uint8_t id) const;
|
const std::string& Hyperlink(uint8_t id) const;
|
||||||
|
|
||||||
|
using SelectionStyle = std::function<void(Pixel&)>;
|
||||||
|
const SelectionStyle& GetSelectionStyle() const;
|
||||||
|
void SetSelectionStyle(SelectionStyle decorator);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Cursor cursor_;
|
Cursor cursor_;
|
||||||
std::vector<std::string> hyperlinks_ = {""};
|
std::vector<std::string> hyperlinks_ = {""};
|
||||||
|
|
||||||
|
// The current selection style. This is overridden by various dom elements.
|
||||||
|
SelectionStyle selection_style_ = [](Pixel& pixel) {
|
||||||
|
pixel.inverted ^= true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ftxui
|
} // namespace ftxui
|
||||||
|
@ -577,19 +577,13 @@ void ScreenInteractive::ForceHandleCtrlZ(bool force) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Returns the content of the current selection
|
/// @brief Returns the content of the current selection
|
||||||
std::string ScreenInteractive::GetSelectedContent(Component component)
|
std::string ScreenInteractive::GetSelectedContent(Component component) {
|
||||||
{
|
|
||||||
Selection selection(selection_start_x_, selection_start_y_, //
|
Selection selection(selection_start_x_, selection_start_y_, //
|
||||||
selection_end_x_, selection_end_y_, selection_options_);
|
selection_end_x_, selection_end_y_);
|
||||||
|
|
||||||
return GetNodeSelectedContent(*this, component->Render().get(), selection);
|
return GetNodeSelectedContent(*this, component->Render().get(), selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenInteractive::setSelectionOptions(SelectionOption option)
|
|
||||||
{
|
|
||||||
selection_options_ = std::move(option);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Return the currently active screen, or null if none.
|
/// @brief Return the currently active screen, or null if none.
|
||||||
// static
|
// static
|
||||||
ScreenInteractive* ScreenInteractive::Active() {
|
ScreenInteractive* ScreenInteractive::Active() {
|
||||||
@ -966,14 +960,9 @@ void ScreenInteractive::Draw(Component component) {
|
|||||||
previous_frame_resized_ = resized;
|
previous_frame_resized_ = resized;
|
||||||
|
|
||||||
Selection selection(selection_start_x_, selection_start_y_, //
|
Selection selection(selection_start_x_, selection_start_y_, //
|
||||||
selection_end_x_, selection_end_y_, selection_options_);
|
selection_end_x_, selection_end_y_);
|
||||||
Render(*this, document.get(), selection);
|
Render(*this, document.get(), selection);
|
||||||
|
|
||||||
if(selection_changed == true)
|
|
||||||
{
|
|
||||||
selection_options_.on_change();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set cursor position for user using tools to insert CJK characters.
|
// Set cursor position for user using tools to insert CJK characters.
|
||||||
{
|
{
|
||||||
const int dx = dimx_ - 1 - cursor_.x + int(dimx_ != terminal.dimx);
|
const int dx = dimx_ - 1 - cursor_.x + int(dimx_ != terminal.dimx);
|
||||||
|
@ -26,12 +26,11 @@ class Unselectable : public NodeDecorator {
|
|||||||
/// @param start_y The y coordinate of the start of the selection.
|
/// @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_x The x coordinate of the end of the selection.
|
||||||
/// @param end_y The y 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, SelectionOption option)
|
Selection::Selection(int start_x, int start_y, int end_x, int end_y)
|
||||||
: start_x_(start_x),
|
: start_x_(start_x),
|
||||||
start_y_(start_y),
|
start_y_(start_y),
|
||||||
end_x_(end_x),
|
end_x_(end_x),
|
||||||
end_y_(end_y),
|
end_y_(end_y),
|
||||||
option(option),
|
|
||||||
box_{
|
box_{
|
||||||
std::min(start_x, end_x),
|
std::min(start_x, end_x),
|
||||||
std::max(start_x, end_x),
|
std::max(start_x, end_x),
|
||||||
@ -45,12 +44,6 @@ const Box& Selection::GetBox() const {
|
|||||||
return box_;
|
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.
|
/// @brief Saturate the selection to be inside the box.
|
||||||
/// This is called by `hbox` to propagate the selection to its children.
|
/// This is called by `hbox` to propagate the selection to its children.
|
||||||
/// @param box The box to saturate the selection in.
|
/// @param box The box to saturate the selection in.
|
||||||
@ -84,7 +77,7 @@ Selection Selection::SaturateHorizontal(Box box) {
|
|||||||
end_y = box.y_min;
|
end_y = box.y_min;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Selection(start_x, start_y, end_x, end_y, option);
|
return Selection(start_x, start_y, end_x, end_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Saturate the selection to be inside the box.
|
/// @brief Saturate the selection to be inside the box.
|
||||||
@ -121,26 +114,7 @@ Selection Selection::SaturateVertical(Box box) {
|
|||||||
end_y = box.y_min;
|
end_y = box.y_min;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Selection(start_x, start_y, end_x, end_y, option);
|
return Selection(start_x, start_y, end_x, end_y);
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Add a filter that will invert the foreground and the background
|
|
||||||
/// colors.
|
|
||||||
/// @ingroup dom
|
|
||||||
Element unselectable(Element child) {
|
|
||||||
return std::make_shared<Unselectable>(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
|
} // namespace ftxui
|
||||||
|
@ -4,15 +4,14 @@
|
|||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <csignal> // for raise, SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM
|
#include <csignal> // for raise, SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM
|
||||||
|
|
||||||
#include "ftxui/dom/elements.hpp" // for text
|
#include "ftxui/component/component.hpp" // for Input, Renderer, Vertical
|
||||||
#include "ftxui/dom/node.hpp" // for Render
|
#include "ftxui/component/event.hpp" // for Event
|
||||||
#include "ftxui/screen/screen.hpp" // for Screen
|
|
||||||
#include "ftxui/component/event.hpp" // for Event
|
|
||||||
#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed, Mouse::Released
|
|
||||||
#include "ftxui/component/component.hpp" // for Input, Renderer, Vertical
|
|
||||||
#include "ftxui/component/screen_interactive.hpp"
|
|
||||||
#include "ftxui/component/loop.hpp" // for Loop
|
#include "ftxui/component/loop.hpp" // for Loop
|
||||||
|
#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed, Mouse::Released
|
||||||
|
#include "ftxui/component/screen_interactive.hpp"
|
||||||
|
#include "ftxui/dom/elements.hpp" // for text
|
||||||
|
#include "ftxui/dom/node.hpp" // for Render
|
||||||
|
#include "ftxui/screen/screen.hpp" // for Screen
|
||||||
|
|
||||||
// NOLINTBEGIN
|
// NOLINTBEGIN
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
@ -43,12 +42,8 @@ Event MouseReleased(int x, int y) {
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
TEST(SelectionTest, DefaultSelection) {
|
TEST(SelectionTest, DefaultSelection) {
|
||||||
|
auto component = Renderer([&] { return text("Lorem ipsum dolor"); });
|
||||||
auto component = Renderer([&] {
|
|
||||||
return text("Lorem ipsum dolor");
|
|
||||||
});
|
|
||||||
|
|
||||||
auto screen = ScreenInteractive::FixedSize(20, 1);
|
auto screen = ScreenInteractive::FixedSize(20, 1);
|
||||||
|
|
||||||
@ -64,24 +59,12 @@ TEST(SelectionTest, DefaultSelection) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(SelectionTest, CallbackSelection) {
|
TEST(SelectionTest, CallbackSelection) {
|
||||||
|
|
||||||
int selectionChangeCounter = 0;
|
int selectionChangeCounter = 0;
|
||||||
|
|
||||||
auto component = Renderer([&] {
|
auto component = Renderer([&] { return text("Lorem ipsum dolor"); });
|
||||||
return text("Lorem ipsum dolor");
|
|
||||||
});
|
|
||||||
|
|
||||||
auto screen = ScreenInteractive::FixedSize(20, 1);
|
auto screen = ScreenInteractive::FixedSize(20, 1);
|
||||||
|
|
||||||
screen.setSelectionOptions({
|
|
||||||
.transform = [](Pixel& pixel) {
|
|
||||||
pixel.underlined_double = true;
|
|
||||||
},
|
|
||||||
.on_change = [&] {
|
|
||||||
selectionChangeCounter++;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Loop loop(&screen, component);
|
Loop loop(&screen, component);
|
||||||
|
|
||||||
loop.RunOnce();
|
loop.RunOnce();
|
||||||
@ -96,34 +79,22 @@ TEST(SelectionTest, CallbackSelection) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(SelectionTest, StyleSelection) {
|
TEST(SelectionTest, StyleSelection) {
|
||||||
|
|
||||||
int selectionChangeCounter = 0;
|
int selectionChangeCounter = 0;
|
||||||
|
|
||||||
auto component = Renderer([&] {
|
auto component = Renderer([&] { return text("Lorem ipsum dolor"); });
|
||||||
return text("Lorem ipsum dolor");
|
|
||||||
});
|
|
||||||
|
|
||||||
auto screen = ScreenInteractive::FixedSize(20, 1);
|
auto screen = ScreenInteractive::FixedSize(20, 1);
|
||||||
|
|
||||||
Selection selection(2, 0, 9, 0, {
|
Selection selection(2, 0, 9, 0);
|
||||||
.transform = [](Pixel& pixel) {
|
|
||||||
pixel.underlined_double = true;
|
|
||||||
},
|
|
||||||
.on_change = [&] {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Render(screen, component->Render().get(), selection);
|
Render(screen, component->Render().get(), selection);
|
||||||
|
|
||||||
EXPECT_EQ(screen.ToString(), "Lo\x1B[21mrem ipsu\x1B[24mm dolor ");
|
EXPECT_EQ(screen.ToString(), "Lo\x1B[21mrem ipsu\x1B[24mm dolor ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(SelectionTest, VBoxSelection) {
|
TEST(SelectionTest, VBoxSelection) {
|
||||||
|
|
||||||
auto component = Renderer([&] {
|
auto component = Renderer([&] {
|
||||||
return vbox({ text("Lorem ipsum dolor"),
|
return vbox({text("Lorem ipsum dolor"), text("Ut enim ad minim")});
|
||||||
text("Ut enim ad minim")});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
auto screen = ScreenInteractive::FixedSize(20, 2);
|
auto screen = ScreenInteractive::FixedSize(20, 2);
|
||||||
@ -132,15 +103,15 @@ TEST(SelectionTest, VBoxSelection) {
|
|||||||
|
|
||||||
Render(screen, component->Render().get(), selection);
|
Render(screen, component->Render().get(), selection);
|
||||||
|
|
||||||
EXPECT_EQ(screen.ToString(), "Lo\x1B[7mrem ipsum dolor\x1B[27m \r\n\x1B[7mUt \x1B[27menim ad minim ");
|
EXPECT_EQ(screen.ToString(),
|
||||||
|
"Lo\x1B[7mrem ipsum dolor\x1B[27m \r\n\x1B[7mUt \x1B[27menim ad "
|
||||||
|
"minim ");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(SelectionTest, VBoxSaturatedSelection) {
|
TEST(SelectionTest, VBoxSaturatedSelection) {
|
||||||
|
|
||||||
auto component = Renderer([&] {
|
auto component = Renderer([&] {
|
||||||
return vbox({ text("Lorem ipsum dolor"),
|
return vbox({text("Lorem ipsum dolor"), text("Ut enim ad minim"),
|
||||||
text("Ut enim ad minim"),
|
text("Duis aute irure")});
|
||||||
text("Duis aute irure")});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
auto screen = ScreenInteractive::FixedSize(20, 3);
|
auto screen = ScreenInteractive::FixedSize(20, 3);
|
||||||
@ -149,15 +120,14 @@ TEST(SelectionTest, VBoxSaturatedSelection) {
|
|||||||
|
|
||||||
Render(screen, component->Render().get(), selection);
|
Render(screen, component->Render().get(), selection);
|
||||||
|
|
||||||
EXPECT_EQ(screen.ToString(), "Lo\x1B[7mrem ipsum dolor\x1B[27m \r\n\x1B[7mUt enim ad minim\x1B[27m \r\n\x1B[7mDui\x1B[27ms aute irure ");
|
EXPECT_EQ(screen.ToString(),
|
||||||
|
"Lo\x1B[7mrem ipsum dolor\x1B[27m \r\n\x1B[7mUt enim ad "
|
||||||
|
"minim\x1B[27m \r\n\x1B[7mDui\x1B[27ms aute irure ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(SelectionTest, HBoxSelection) {
|
TEST(SelectionTest, HBoxSelection) {
|
||||||
|
|
||||||
auto component = Renderer([&] {
|
auto component = Renderer([&] {
|
||||||
return hbox({ text("Lorem ipsum dolor"),
|
return hbox({text("Lorem ipsum dolor"), text("Ut enim ad minim")});
|
||||||
text("Ut enim ad minim")});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
auto screen = ScreenInteractive::FixedSize(40, 1);
|
auto screen = ScreenInteractive::FixedSize(40, 1);
|
||||||
@ -166,15 +136,14 @@ TEST(SelectionTest, HBoxSelection) {
|
|||||||
|
|
||||||
Render(screen, component->Render().get(), selection);
|
Render(screen, component->Render().get(), selection);
|
||||||
|
|
||||||
EXPECT_EQ(screen.ToString(), "Lo\x1B[7mrem ipsum dolorUt e\x1B[27mnim ad minim ");
|
EXPECT_EQ(screen.ToString(),
|
||||||
|
"Lo\x1B[7mrem ipsum dolorUt e\x1B[27mnim ad minim ");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(SelectionTest, HBoxSaturatedSelection) {
|
TEST(SelectionTest, HBoxSaturatedSelection) {
|
||||||
|
|
||||||
auto component = Renderer([&] {
|
auto component = Renderer([&] {
|
||||||
return hbox({ text("Lorem ipsum dolor"),
|
return hbox({text("Lorem ipsum dolor"), text("Ut enim ad minim"),
|
||||||
text("Ut enim ad minim"),
|
text("Duis aute irure")});
|
||||||
text("Duis aute irure")});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
auto screen = ScreenInteractive::FixedSize(60, 1);
|
auto screen = ScreenInteractive::FixedSize(60, 1);
|
||||||
@ -183,7 +152,9 @@ TEST(SelectionTest, HBoxSaturatedSelection) {
|
|||||||
|
|
||||||
Render(screen, component->Render().get(), selection);
|
Render(screen, component->Render().get(), selection);
|
||||||
|
|
||||||
EXPECT_EQ(screen.ToString(), "Lo\x1B[7mrem ipsum dolorUt enim ad minimDui\x1B[27ms aute irure ");
|
EXPECT_EQ(screen.ToString(),
|
||||||
|
"Lo\x1B[7mrem ipsum dolorUt enim ad minimDui\x1B[27ms aute irure "
|
||||||
|
" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ftxui
|
} // namespace ftxui
|
||||||
|
@ -39,8 +39,6 @@ class Text : public Node {
|
|||||||
has_selection = true;
|
has_selection = true;
|
||||||
selection_start_ = selection_saturated.GetBox().x_min;
|
selection_start_ = selection_saturated.GetBox().x_min;
|
||||||
selection_end_ = selection_saturated.GetBox().x_max;
|
selection_end_ = selection_saturated.GetBox().x_max;
|
||||||
|
|
||||||
selectionTransform = selection.GetOption().transform;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Render(Screen& screen) override {
|
void Render(Screen& screen) override {
|
||||||
@ -61,6 +59,7 @@ class Text : public Node {
|
|||||||
screen.PixelAt(x, y).character = cell;
|
screen.PixelAt(x, y).character = cell;
|
||||||
|
|
||||||
if (has_selection) {
|
if (has_selection) {
|
||||||
|
auto selectionTransform = screen.GetSelectionStyle();
|
||||||
if ((x >= selection_start_) && (x <= selection_end_)) {
|
if ((x >= selection_start_) && (x <= selection_end_)) {
|
||||||
selectionTransform(screen.PixelAt(x, y));
|
selectionTransform(screen.PixelAt(x, y));
|
||||||
}
|
}
|
||||||
|
@ -544,4 +544,16 @@ const std::string& Screen::Hyperlink(std::uint8_t id) const {
|
|||||||
return hyperlinks_[id];
|
return hyperlinks_[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Return the current selection style.
|
||||||
|
/// @see SetSelectionStyle
|
||||||
|
const Screen::SelectionStyle& Screen::GetSelectionStyle() const {
|
||||||
|
return selection_style_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Set the current selection style.
|
||||||
|
/// @see GetSelectionStyle
|
||||||
|
void Screen::SetSelectionStyle(SelectionStyle decorator) {
|
||||||
|
selection_style_ = decorator;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ftxui
|
} // namespace ftxui
|
||||||
|
Loading…
Reference in New Issue
Block a user