mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2024-11-22 02:34:21 +08:00
Restore cursor shape on exit. (#793)
Fixed: https://github.com/ArthurSonzogni/FTXUI/issues/792
This commit is contained in:
parent
bfadcb7165
commit
348c3853d4
@ -10,6 +10,7 @@ Checks: "*,
|
|||||||
-android-*,
|
-android-*,
|
||||||
-bugprone-easily-swappable-parameters,
|
-bugprone-easily-swappable-parameters,
|
||||||
-cppcoreguidelines-non-private-member-variables-in-classes,
|
-cppcoreguidelines-non-private-member-variables-in-classes,
|
||||||
|
-cppcoreguidelines-pro-type-union-access,
|
||||||
-fuchsia-*,
|
-fuchsia-*,
|
||||||
-google-*,
|
-google-*,
|
||||||
-hicpp-signed-bitwise,
|
-hicpp-signed-bitwise,
|
||||||
|
@ -32,6 +32,7 @@ current (development)
|
|||||||
alternate screen.
|
alternate screen.
|
||||||
- Bugfix: `Input` `onchange` was not called on backspace or delete key.
|
- Bugfix: `Input` `onchange` was not called on backspace or delete key.
|
||||||
Fixed by @chrysante in chrysante in PR #776.
|
Fixed by @chrysante in chrysante in PR #776.
|
||||||
|
- Bugfix: Propertly restore cursor shape on exit. See #792.
|
||||||
|
|
||||||
### Dom
|
### Dom
|
||||||
- Feature: Add `hscroll_indicator`. It display an horizontal indicator
|
- Feature: Add `hscroll_indicator`. It display an horizontal indicator
|
||||||
|
@ -33,7 +33,8 @@ struct Event {
|
|||||||
static Event Character(wchar_t);
|
static Event Character(wchar_t);
|
||||||
static Event Special(std::string);
|
static Event Special(std::string);
|
||||||
static Event Mouse(std::string, Mouse mouse);
|
static Event Mouse(std::string, Mouse mouse);
|
||||||
static Event CursorReporting(std::string, int x, int y);
|
static Event CursorPosition(std::string, int x, int y); // Internal
|
||||||
|
static Event CursorShape(std::string, int shape); // Internal
|
||||||
|
|
||||||
// --- Arrow ---
|
// --- Arrow ---
|
||||||
static const Event ArrowLeft;
|
static const Event ArrowLeft;
|
||||||
@ -66,20 +67,24 @@ struct Event {
|
|||||||
static const Event Custom;
|
static const Event Custom;
|
||||||
|
|
||||||
//--- Method section ---------------------------------------------------------
|
//--- Method section ---------------------------------------------------------
|
||||||
|
bool operator==(const Event& other) const { return input_ == other.input_; }
|
||||||
|
bool operator!=(const Event& other) const { return !operator==(other); }
|
||||||
|
|
||||||
|
const std::string& input() const { return input_; }
|
||||||
|
|
||||||
bool is_character() const { return type_ == Type::Character; }
|
bool is_character() const { return type_ == Type::Character; }
|
||||||
std::string character() const { return input_; }
|
std::string character() const { return input_; }
|
||||||
|
|
||||||
bool is_mouse() const { return type_ == Type::Mouse; }
|
bool is_mouse() const { return type_ == Type::Mouse; }
|
||||||
struct Mouse& mouse() { return data_.mouse; }
|
struct Mouse& mouse() { return data_.mouse; }
|
||||||
|
|
||||||
bool is_cursor_reporting() const { return type_ == Type::CursorReporting; }
|
// --- Internal Method section -----------------------------------------------
|
||||||
|
bool is_cursor_position() const { return type_ == Type::CursorPosition; }
|
||||||
int cursor_x() const { return data_.cursor.x; }
|
int cursor_x() const { return data_.cursor.x; }
|
||||||
int cursor_y() const { return data_.cursor.y; }
|
int cursor_y() const { return data_.cursor.y; }
|
||||||
|
|
||||||
const std::string& input() const { return input_; }
|
bool is_cursor_shape() const { return type_ == Type::CursorShape; }
|
||||||
|
int cursor_shape() const { return data_.cursor_shape; }
|
||||||
bool operator==(const Event& other) const { return input_ == other.input_; }
|
|
||||||
bool operator!=(const Event& other) const { return !operator==(other); }
|
|
||||||
|
|
||||||
//--- State section ----------------------------------------------------------
|
//--- State section ----------------------------------------------------------
|
||||||
ScreenInteractive* screen_ = nullptr;
|
ScreenInteractive* screen_ = nullptr;
|
||||||
@ -91,7 +96,8 @@ struct Event {
|
|||||||
Unknown,
|
Unknown,
|
||||||
Character,
|
Character,
|
||||||
Mouse,
|
Mouse,
|
||||||
CursorReporting,
|
CursorPosition,
|
||||||
|
CursorShape,
|
||||||
};
|
};
|
||||||
Type type_ = Type::Unknown;
|
Type type_ = Type::Unknown;
|
||||||
|
|
||||||
@ -103,6 +109,7 @@ struct Event {
|
|||||||
union {
|
union {
|
||||||
struct Mouse mouse;
|
struct Mouse mouse;
|
||||||
struct Cursor cursor;
|
struct Cursor cursor;
|
||||||
|
int cursor_shape;
|
||||||
} data_ = {};
|
} data_ = {};
|
||||||
|
|
||||||
std::string input_;
|
std::string input_;
|
||||||
|
@ -114,6 +114,9 @@ class ScreenInteractive : public Screen {
|
|||||||
|
|
||||||
bool frame_valid_ = false;
|
bool frame_valid_ = false;
|
||||||
|
|
||||||
|
// The style of the cursor to restore on exit.
|
||||||
|
int cursor_reset_shape_ = 1;
|
||||||
|
|
||||||
Mouse latest_mouse_event_;
|
Mouse latest_mouse_event_;
|
||||||
friend class Loop;
|
friend class Loop;
|
||||||
|
|
||||||
|
@ -49,6 +49,16 @@ Event Event::Mouse(std::string input, struct Mouse mouse) {
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief An event corresponding to a terminal DCS (Device Control String).
|
||||||
|
// static
|
||||||
|
Event Event::CursorShape(std::string input, int shape) {
|
||||||
|
Event event;
|
||||||
|
event.input_ = std::move(input);
|
||||||
|
event.type_ = Type::CursorShape;
|
||||||
|
event.data_.cursor_shape = shape; // NOLINT
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief An custom event whose meaning is defined by the user of the library.
|
/// @brief An custom event whose meaning is defined by the user of the library.
|
||||||
/// @param input An arbitrary sequence of character defined by the developer.
|
/// @param input An arbitrary sequence of character defined by the developer.
|
||||||
/// @ingroup component.
|
/// @ingroup component.
|
||||||
@ -61,10 +71,10 @@ Event Event::Special(std::string input) {
|
|||||||
|
|
||||||
/// @internal
|
/// @internal
|
||||||
// static
|
// static
|
||||||
Event Event::CursorReporting(std::string input, int x, int y) {
|
Event Event::CursorPosition(std::string input, int x, int y) {
|
||||||
Event event;
|
Event event;
|
||||||
event.input_ = std::move(input);
|
event.input_ = std::move(input);
|
||||||
event.type_ = Type::CursorReporting;
|
event.type_ = Type::CursorPosition;
|
||||||
event.data_.cursor = {x, y}; // NOLINT
|
event.data_.cursor = {x, y}; // NOLINT
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
@ -253,7 +253,17 @@ void InstallSignalHandler(int sig) {
|
|||||||
[=] { std::ignore = std::signal(sig, old_signal_handler); });
|
[=] { std::ignore = std::signal(sig, old_signal_handler); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CSI: Control Sequence Introducer
|
||||||
const std::string CSI = "\x1b["; // NOLINT
|
const std::string CSI = "\x1b["; // NOLINT
|
||||||
|
//
|
||||||
|
// DCS: Device Control String
|
||||||
|
const std::string DCS = "\x1bP"; // NOLINT
|
||||||
|
// ST: String Terminator
|
||||||
|
const std::string ST = "\x1b\\"; // NOLINT
|
||||||
|
|
||||||
|
// DECRQSS: Request Status String
|
||||||
|
// DECSCUSR: Set Cursor Style
|
||||||
|
const std::string DECRQSS_DECSCUSR = DCS + "$q q" + ST; // NOLINT
|
||||||
|
|
||||||
// DEC: Digital Equipment Corporation
|
// DEC: Digital Equipment Corporation
|
||||||
enum class DECMode {
|
enum class DECMode {
|
||||||
@ -566,6 +576,14 @@ void ScreenInteractive::Install() {
|
|||||||
|
|
||||||
on_exit_functions.push([this] { ExitLoopClosure()(); });
|
on_exit_functions.push([this] { ExitLoopClosure()(); });
|
||||||
|
|
||||||
|
// Request the terminal to report the current cursor shape. We will restore it
|
||||||
|
// on exit.
|
||||||
|
std::cout << DECRQSS_DECSCUSR;
|
||||||
|
on_exit_functions.push([=] {
|
||||||
|
std::cout << "\033[?25h"; // Enable cursor.
|
||||||
|
std::cout << "\033[" + std::to_string(cursor_reset_shape_) + " q";
|
||||||
|
});
|
||||||
|
|
||||||
// Install signal handlers to restore the terminal state on exit. The default
|
// Install signal handlers to restore the terminal state on exit. The default
|
||||||
// signal handlers are restored on exit.
|
// signal handlers are restored on exit.
|
||||||
for (const int signal : {SIGTERM, SIGSEGV, SIGINT, SIGILL, SIGABRT, SIGFPE}) {
|
for (const int signal : {SIGTERM, SIGSEGV, SIGINT, SIGILL, SIGABRT, SIGFPE}) {
|
||||||
@ -640,11 +658,6 @@ void ScreenInteractive::Install() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
on_exit_functions.push([=] {
|
|
||||||
std::cout << "\033[?25h"; // Enable cursor.
|
|
||||||
std::cout << "\033[?1 q"; // Cursor block blinking.
|
|
||||||
});
|
|
||||||
|
|
||||||
disable({
|
disable({
|
||||||
// DECMode::kCursor,
|
// DECMode::kCursor,
|
||||||
DECMode::kLineWrap,
|
DECMode::kLineWrap,
|
||||||
@ -700,18 +713,24 @@ void ScreenInteractive::RunOnce(Component component) {
|
|||||||
|
|
||||||
// private
|
// private
|
||||||
void ScreenInteractive::HandleTask(Component component, Task& task) {
|
void ScreenInteractive::HandleTask(Component component, Task& task) {
|
||||||
// clang-format off
|
std::visit(
|
||||||
std::visit([&](auto&& arg) {
|
[&](auto&& arg) {
|
||||||
using T = std::decay_t<decltype(arg)>;
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
// Handle Event.
|
// Handle Event.
|
||||||
if constexpr (std::is_same_v<T, Event>) {
|
if constexpr (std::is_same_v<T, Event>) {
|
||||||
if (arg.is_cursor_reporting()) {
|
if (arg.is_cursor_position()) {
|
||||||
cursor_x_ = arg.cursor_x();
|
cursor_x_ = arg.cursor_x();
|
||||||
cursor_y_ = arg.cursor_y();
|
cursor_y_ = arg.cursor_y();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arg.is_cursor_shape()) {
|
||||||
|
cursor_reset_shape_= arg.cursor_shape();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (arg.is_mouse()) {
|
if (arg.is_mouse()) {
|
||||||
arg.mouse().x -= cursor_x_;
|
arg.mouse().x -= cursor_x_;
|
||||||
arg.mouse().y -= cursor_y_;
|
arg.mouse().y -= cursor_y_;
|
||||||
|
@ -150,10 +150,15 @@ void TerminalInputParser::Send(TerminalInputParser::Output output) {
|
|||||||
pending_.clear();
|
pending_.clear();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case CURSOR_REPORTING:
|
case CURSOR_POSITION:
|
||||||
out_->Send(Event::CursorReporting(std::move(pending_), // NOLINT
|
out_->Send(Event::CursorPosition(std::move(pending_), // NOLINT
|
||||||
output.cursor.x, // NOLINT
|
output.cursor.x, // NOLINT
|
||||||
output.cursor.y)); // NOLINT
|
output.cursor.y)); // NOLINT
|
||||||
|
pending_.clear();
|
||||||
|
return;
|
||||||
|
|
||||||
|
case CURSOR_SHAPE:
|
||||||
|
out_->Send(Event::CursorShape(std::move(pending_), output.cursor_shape));
|
||||||
pending_.clear();
|
pending_.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -286,6 +291,7 @@ TerminalInputParser::Output TerminalInputParser::ParseESC() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ESC P ... ESC BACKSLASH
|
||||||
TerminalInputParser::Output TerminalInputParser::ParseDCS() {
|
TerminalInputParser::Output TerminalInputParser::ParseDCS() {
|
||||||
// Parse until the string terminator ST.
|
// Parse until the string terminator ST.
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -305,6 +311,16 @@ TerminalInputParser::Output TerminalInputParser::ParseDCS() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pending_.size() == 10 && //
|
||||||
|
pending_[2] == '1' && //
|
||||||
|
pending_[3] == '$' && //
|
||||||
|
pending_[4] == 'r' && //
|
||||||
|
true) {
|
||||||
|
Output output(CURSOR_SHAPE);
|
||||||
|
output.cursor_shape = pending_[5] - '0';
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
return SPECIAL;
|
return SPECIAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -351,7 +367,7 @@ TerminalInputParser::Output TerminalInputParser::ParseCSI() {
|
|||||||
case 'm':
|
case 'm':
|
||||||
return ParseMouse(altered, false, std::move(arguments));
|
return ParseMouse(altered, false, std::move(arguments));
|
||||||
case 'R':
|
case 'R':
|
||||||
return ParseCursorReporting(std::move(arguments));
|
return ParseCursorPosition(std::move(arguments));
|
||||||
default:
|
default:
|
||||||
return SPECIAL;
|
return SPECIAL;
|
||||||
}
|
}
|
||||||
@ -405,12 +421,12 @@ TerminalInputParser::Output TerminalInputParser::ParseMouse( // NOLINT
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTNEXTLINE
|
// NOLINTNEXTLINE
|
||||||
TerminalInputParser::Output TerminalInputParser::ParseCursorReporting(
|
TerminalInputParser::Output TerminalInputParser::ParseCursorPosition(
|
||||||
std::vector<int> arguments) {
|
std::vector<int> arguments) {
|
||||||
if (arguments.size() != 2) {
|
if (arguments.size() != 2) {
|
||||||
return SPECIAL;
|
return SPECIAL;
|
||||||
}
|
}
|
||||||
Output output(CURSOR_REPORTING);
|
Output output(CURSOR_POSITION);
|
||||||
output.cursor.y = arguments[0]; // NOLINT
|
output.cursor.y = arguments[0]; // NOLINT
|
||||||
output.cursor.x = arguments[1]; // NOLINT
|
output.cursor.x = arguments[1]; // NOLINT
|
||||||
return output;
|
return output;
|
||||||
|
@ -31,12 +31,13 @@ class TerminalInputParser {
|
|||||||
UNCOMPLETED,
|
UNCOMPLETED,
|
||||||
DROP,
|
DROP,
|
||||||
CHARACTER,
|
CHARACTER,
|
||||||
SPECIAL,
|
|
||||||
MOUSE,
|
MOUSE,
|
||||||
CURSOR_REPORTING,
|
CURSOR_POSITION,
|
||||||
|
CURSOR_SHAPE,
|
||||||
|
SPECIAL,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CursorReporting {
|
struct CursorPosition {
|
||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
};
|
};
|
||||||
@ -45,7 +46,8 @@ class TerminalInputParser {
|
|||||||
Type type;
|
Type type;
|
||||||
union {
|
union {
|
||||||
Mouse mouse;
|
Mouse mouse;
|
||||||
CursorReporting cursor;
|
CursorPosition cursor;
|
||||||
|
int cursor_shape;
|
||||||
};
|
};
|
||||||
|
|
||||||
Output(Type t) : type(t) {}
|
Output(Type t) : type(t) {}
|
||||||
@ -59,7 +61,7 @@ class TerminalInputParser {
|
|||||||
Output ParseCSI();
|
Output ParseCSI();
|
||||||
Output ParseOSC();
|
Output ParseOSC();
|
||||||
Output ParseMouse(bool altered, bool pressed, std::vector<int> arguments);
|
Output ParseMouse(bool altered, bool pressed, std::vector<int> arguments);
|
||||||
Output ParseCursorReporting(std::vector<int> arguments);
|
Output ParseCursorPosition(std::vector<int> arguments);
|
||||||
|
|
||||||
Sender<Task> out_;
|
Sender<Task> out_;
|
||||||
int position_ = -1;
|
int position_ = -1;
|
||||||
|
@ -146,7 +146,7 @@ TEST(Event, MouseReporting) {
|
|||||||
|
|
||||||
Task received;
|
Task received;
|
||||||
EXPECT_TRUE(event_receiver->Receive(&received));
|
EXPECT_TRUE(event_receiver->Receive(&received));
|
||||||
EXPECT_TRUE(std::get<Event>(received).is_cursor_reporting());
|
EXPECT_TRUE(std::get<Event>(received).is_cursor_position());
|
||||||
EXPECT_EQ(42, std::get<Event>(received).cursor_x());
|
EXPECT_EQ(42, std::get<Event>(received).cursor_x());
|
||||||
EXPECT_EQ(12, std::get<Event>(received).cursor_y());
|
EXPECT_EQ(12, std::get<Event>(received).cursor_y());
|
||||||
EXPECT_FALSE(event_receiver->Receive(&received));
|
EXPECT_FALSE(event_receiver->Receive(&received));
|
||||||
@ -446,5 +446,28 @@ TEST(Event, Special) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Event, DeviceControlString) {
|
||||||
|
auto event_receiver = MakeReceiver<Task>();
|
||||||
|
{
|
||||||
|
auto parser = TerminalInputParser(event_receiver->MakeSender());
|
||||||
|
parser.Add(27); // ESC
|
||||||
|
parser.Add(80); // P
|
||||||
|
parser.Add(49); // 1
|
||||||
|
parser.Add(36); // $
|
||||||
|
parser.Add(114); // r
|
||||||
|
parser.Add(49); // 1
|
||||||
|
parser.Add(32); // SP
|
||||||
|
parser.Add(113); // q
|
||||||
|
parser.Add(27); // ESC
|
||||||
|
parser.Add(92); // (backslash)
|
||||||
|
}
|
||||||
|
|
||||||
|
Task received;
|
||||||
|
EXPECT_TRUE(event_receiver->Receive(&received));
|
||||||
|
EXPECT_TRUE(std::get<Event>(received).is_cursor_shape());
|
||||||
|
EXPECT_EQ(1, std::get<Event>(received).cursor_shape());
|
||||||
|
EXPECT_FALSE(event_receiver->Receive(&received));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ftxui
|
} // namespace ftxui
|
||||||
// NOLINTEND
|
// NOLINTEND
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
|
|
||||||
#include "ftxui/dom/elements.hpp" // for operator|, Element, operator|=, text, vbox, Elements, border, focus, frame, vscroll_indicator
|
#include "ftxui/dom/elements.hpp" // for operator|, Element, operator|=, text, vbox, Elements, border, focus, frame, vscroll_indicator
|
||||||
#include "ftxui/dom/node.hpp" // for Render
|
#include "ftxui/dom/node.hpp" // for Render
|
||||||
|
#include "ftxui/screen/color.hpp" // for Color, Color::Red
|
||||||
#include "ftxui/screen/screen.hpp" // for Screen
|
#include "ftxui/screen/screen.hpp" // for Screen
|
||||||
#include "ftxui/screen/color.hpp" // for Color, Color::Red
|
|
||||||
|
|
||||||
// NOLINTBEGIN
|
// NOLINTBEGIN
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
@ -129,7 +129,6 @@ TEST(ScrollIndicator, BasicVertical) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(ScrollIndicator, VerticalColorable) {
|
TEST(ScrollIndicator, VerticalColorable) {
|
||||||
|
|
||||||
// The list we generate looks like this
|
// The list we generate looks like this
|
||||||
// "╭────╮\r\n"
|
// "╭────╮\r\n"
|
||||||
// "│0 ┃│\r\n"
|
// "│0 ┃│\r\n"
|
||||||
@ -147,7 +146,6 @@ TEST(ScrollIndicator, VerticalColorable) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(ScrollIndicator, VerticalBackgroundColorable) {
|
TEST(ScrollIndicator, VerticalBackgroundColorable) {
|
||||||
|
|
||||||
// The list we generate looks like this
|
// The list we generate looks like this
|
||||||
// "╭────╮\r\n"
|
// "╭────╮\r\n"
|
||||||
// "│0 ┃│\r\n"
|
// "│0 ┃│\r\n"
|
||||||
@ -165,7 +163,6 @@ TEST(ScrollIndicator, VerticalBackgroundColorable) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(ScrollIndicator, VerticalFullColorable) {
|
TEST(ScrollIndicator, VerticalFullColorable) {
|
||||||
|
|
||||||
// The list we generate looks like this
|
// The list we generate looks like this
|
||||||
// "╭────╮\r\n"
|
// "╭────╮\r\n"
|
||||||
// "│0 ┃│\r\n"
|
// "│0 ┃│\r\n"
|
||||||
@ -174,7 +171,8 @@ TEST(ScrollIndicator, VerticalFullColorable) {
|
|||||||
// "│3 │\r\n"
|
// "│3 │\r\n"
|
||||||
// "╰────╯"
|
// "╰────╯"
|
||||||
|
|
||||||
auto element = MakeVerticalList(0, 10) | color(Color::Red) | bgcolor(Color::Red);
|
auto element =
|
||||||
|
MakeVerticalList(0, 10) | color(Color::Red) | bgcolor(Color::Red);
|
||||||
Screen screen(6, 6);
|
Screen screen(6, 6);
|
||||||
Render(screen, element);
|
Render(screen, element);
|
||||||
|
|
||||||
@ -233,7 +231,6 @@ TEST(ScrollIndicator, BasicHorizontal) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(ScrollIndicator, HorizontalColorable) {
|
TEST(ScrollIndicator, HorizontalColorable) {
|
||||||
|
|
||||||
// The list we generate looks like this
|
// The list we generate looks like this
|
||||||
// "╭────╮\r\n"
|
// "╭────╮\r\n"
|
||||||
// "│5678│\r\n"
|
// "│5678│\r\n"
|
||||||
@ -249,7 +246,6 @@ TEST(ScrollIndicator, HorizontalColorable) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(ScrollIndicator, HorizontalBackgroundColorable) {
|
TEST(ScrollIndicator, HorizontalBackgroundColorable) {
|
||||||
|
|
||||||
// The list we generate looks like this
|
// The list we generate looks like this
|
||||||
// "╭────╮\r\n"
|
// "╭────╮\r\n"
|
||||||
// "│5678│\r\n"
|
// "│5678│\r\n"
|
||||||
@ -265,14 +261,14 @@ TEST(ScrollIndicator, HorizontalBackgroundColorable) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(ScrollIndicator, HorizontalFullColorable) {
|
TEST(ScrollIndicator, HorizontalFullColorable) {
|
||||||
|
|
||||||
// The list we generate looks like this
|
// The list we generate looks like this
|
||||||
// "╭────╮\r\n"
|
// "╭────╮\r\n"
|
||||||
// "│5678│\r\n"
|
// "│5678│\r\n"
|
||||||
// "│ ──│\r\n"
|
// "│ ──│\r\n"
|
||||||
// "╰────╯"
|
// "╰────╯"
|
||||||
|
|
||||||
auto element = MakeHorizontalList(6, 10) | color(Color::Red) | bgcolor(Color::Red);
|
auto element =
|
||||||
|
MakeHorizontalList(6, 10) | color(Color::Red) | bgcolor(Color::Red);
|
||||||
Screen screen(6, 4);
|
Screen screen(6, 4);
|
||||||
Render(screen, element);
|
Render(screen, element);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user