2021-10-16 05:04:11 +08:00
|
|
|
#include "ftxui/dom/table.hpp"
|
|
|
|
|
|
|
|
#include <algorithm> // for max
|
|
|
|
#include <memory> // for allocator, shared_ptr, allocator_traits<>::value_type
|
|
|
|
#include <utility> // for move, swap
|
|
|
|
|
|
|
|
#include "ftxui/dom/elements.hpp" // for Element, operator|, text, separatorCharacter, Elements, BorderStyle, Decorator, emptyElement, size, gridbox, EQUAL, flex, flex_shrink, HEIGHT, WIDTH
|
|
|
|
|
|
|
|
namespace ftxui {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
bool IsCell(int x, int y) {
|
|
|
|
return x % 2 == 1 && y % 2 == 1;
|
|
|
|
}
|
|
|
|
|
2022-03-31 08:17:43 +08:00
|
|
|
// NOLINTNEXTLINE
|
2023-03-16 05:50:27 +08:00
|
|
|
static std::string charset[6][6] = {
|
2023-03-22 20:59:02 +08:00
|
|
|
{"┌", "┐", "└", "┘", "─", "│"}, // LIGHT
|
|
|
|
{"┏", "┓", "┗", "┛", "╍", "╏"}, // DASHED
|
|
|
|
{"┏", "┓", "┗", "┛", "━", "┃"}, // HEAVY
|
|
|
|
{"╔", "╗", "╚", "╝", "═", "║"}, // DOUBLE
|
|
|
|
{"╭", "╮", "╰", "╯", "─", "│"}, // ROUNDED
|
|
|
|
{" ", " ", " ", " ", " ", " "}, // EMPTY
|
2021-10-16 05:04:11 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
int Wrap(int input, int modulo) {
|
|
|
|
input %= modulo;
|
|
|
|
input += modulo;
|
|
|
|
input %= modulo;
|
|
|
|
return input;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Order(int& a, int& b) {
|
2022-03-31 08:17:43 +08:00
|
|
|
if (a >= b) {
|
2021-10-16 05:04:11 +08:00
|
|
|
std::swap(a, b);
|
2022-03-31 08:17:43 +08:00
|
|
|
}
|
2021-10-16 05:04:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
2022-01-16 23:46:32 +08:00
|
|
|
Table::Table() {
|
|
|
|
Initialize({});
|
|
|
|
}
|
|
|
|
|
2021-10-16 05:04:11 +08:00
|
|
|
Table::Table(std::vector<std::vector<std::string>> input) {
|
2022-01-16 23:46:32 +08:00
|
|
|
std::vector<std::vector<Element>> output;
|
2022-02-05 22:03:45 +08:00
|
|
|
for (auto& row : input) {
|
2022-03-31 08:17:43 +08:00
|
|
|
output.emplace_back();
|
2022-01-16 23:46:32 +08:00
|
|
|
auto& output_row = output.back();
|
2022-02-05 22:03:45 +08:00
|
|
|
for (auto& cell : row) {
|
2022-03-31 08:17:43 +08:00
|
|
|
output_row.push_back(text(std::move(cell)));
|
2022-01-16 23:46:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Initialize(std::move(output));
|
|
|
|
}
|
|
|
|
|
|
|
|
Table::Table(std::vector<std::vector<Element>> input) {
|
|
|
|
Initialize(std::move(input));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Table::Initialize(std::vector<std::vector<Element>> input) {
|
2022-03-31 08:17:43 +08:00
|
|
|
input_dim_y_ = (int)input.size();
|
2021-10-16 05:04:11 +08:00
|
|
|
input_dim_x_ = 0;
|
2022-03-31 08:17:43 +08:00
|
|
|
for (auto& row : input) {
|
2021-10-16 05:04:11 +08:00
|
|
|
input_dim_x_ = std::max(input_dim_x_, (int)row.size());
|
2022-03-31 08:17:43 +08:00
|
|
|
}
|
2021-10-16 05:04:11 +08:00
|
|
|
|
|
|
|
dim_y_ = 2 * input_dim_y_ + 1;
|
|
|
|
dim_x_ = 2 * input_dim_x_ + 1;
|
|
|
|
|
|
|
|
// Reserve space.
|
|
|
|
elements_.resize(dim_y_);
|
2022-03-31 08:17:43 +08:00
|
|
|
for (int y = 0; y < dim_y_; ++y) {
|
2021-10-16 05:04:11 +08:00
|
|
|
elements_[y].resize(dim_x_);
|
2022-03-31 08:17:43 +08:00
|
|
|
}
|
2021-10-16 05:04:11 +08:00
|
|
|
|
|
|
|
// Transfert elements_ from |input| toward |elements_|.
|
|
|
|
{
|
|
|
|
int y = 1;
|
|
|
|
for (auto& row : input) {
|
|
|
|
int x = 1;
|
|
|
|
for (auto& cell : row) {
|
2022-01-16 23:46:32 +08:00
|
|
|
elements_[y][x] = std::move(cell);
|
2021-10-16 05:04:11 +08:00
|
|
|
x += 2;
|
|
|
|
}
|
|
|
|
y += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add empty element for the border.
|
|
|
|
for (int y = 0; y < dim_y_; ++y) {
|
|
|
|
for (int x = 0; x < dim_x_; ++x) {
|
|
|
|
auto& element = elements_[y][x];
|
|
|
|
|
|
|
|
if (IsCell(x, y)) {
|
2022-03-31 08:17:43 +08:00
|
|
|
if (!element) {
|
2021-10-16 05:04:11 +08:00
|
|
|
element = emptyElement();
|
2022-03-31 08:17:43 +08:00
|
|
|
}
|
2021-10-16 05:04:11 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
element = emptyElement();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TableSelection Table::SelectRow(int index) {
|
|
|
|
return SelectRectangle(0, -1, index, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
TableSelection Table::SelectRows(int row_min, int row_max) {
|
|
|
|
return SelectRectangle(0, -1, row_min, row_max);
|
|
|
|
}
|
|
|
|
|
|
|
|
TableSelection Table::SelectColumn(int index) {
|
|
|
|
return SelectRectangle(index, index, 0, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
TableSelection Table::SelectColumns(int column_min, int column_max) {
|
|
|
|
return SelectRectangle(column_min, column_max, 0, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
TableSelection Table::SelectCell(int column, int row) {
|
|
|
|
return SelectRectangle(column, column, row, row);
|
|
|
|
}
|
|
|
|
|
|
|
|
TableSelection Table::SelectRectangle(int column_min,
|
|
|
|
int column_max,
|
|
|
|
int row_min,
|
|
|
|
int row_max) {
|
|
|
|
column_min = Wrap(column_min, input_dim_x_);
|
|
|
|
column_max = Wrap(column_max, input_dim_x_);
|
|
|
|
Order(column_min, column_max);
|
|
|
|
row_min = Wrap(row_min, input_dim_y_);
|
|
|
|
row_max = Wrap(row_max, input_dim_y_);
|
|
|
|
Order(row_min, row_max);
|
|
|
|
|
2022-03-31 08:17:43 +08:00
|
|
|
TableSelection output; // NOLINT
|
2021-10-16 05:04:11 +08:00
|
|
|
output.table_ = this;
|
|
|
|
output.x_min_ = 2 * column_min;
|
|
|
|
output.x_max_ = 2 * column_max + 2;
|
|
|
|
output.y_min_ = 2 * row_min;
|
|
|
|
output.y_max_ = 2 * row_max + 2;
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
|
|
|
|
TableSelection Table::SelectAll() {
|
2022-03-31 08:17:43 +08:00
|
|
|
TableSelection output; // NOLINT
|
2021-10-16 05:04:11 +08:00
|
|
|
output.table_ = this;
|
|
|
|
output.x_min_ = 0;
|
|
|
|
output.x_max_ = dim_x_ - 1;
|
|
|
|
output.y_min_ = 0;
|
|
|
|
output.y_max_ = dim_y_ - 1;
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
|
|
|
|
Element Table::Render() {
|
|
|
|
for (int y = 0; y < dim_y_; ++y) {
|
|
|
|
for (int x = 0; x < dim_x_; ++x) {
|
|
|
|
auto& it = elements_[y][x];
|
|
|
|
|
|
|
|
// Line
|
|
|
|
if ((x + y) % 2 == 1) {
|
|
|
|
it = std::move(it) | flex;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cells
|
|
|
|
if ((x % 2) == 1 && (y % 2) == 1) {
|
|
|
|
it = std::move(it) | flex_shrink;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Corners
|
|
|
|
it = std::move(it) | size(WIDTH, EQUAL, 0) | size(HEIGHT, EQUAL, 0);
|
|
|
|
}
|
|
|
|
}
|
2022-05-08 14:34:51 +08:00
|
|
|
dim_x_ = 0;
|
|
|
|
dim_y_ = 0;
|
2021-10-16 05:04:11 +08:00
|
|
|
return gridbox(std::move(elements_));
|
|
|
|
}
|
|
|
|
|
2022-03-31 08:17:43 +08:00
|
|
|
// NOLINTNEXTLINE
|
2021-10-16 05:04:11 +08:00
|
|
|
void TableSelection::Decorate(Decorator decorator) {
|
|
|
|
for (int y = y_min_; y <= y_max_; ++y) {
|
|
|
|
for (int x = x_min_; x <= x_max_; ++x) {
|
|
|
|
Element& e = table_->elements_[y][x];
|
|
|
|
e = std::move(e) | decorator;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-31 08:17:43 +08:00
|
|
|
// NOLINTNEXTLINE
|
2021-10-16 05:04:11 +08:00
|
|
|
void TableSelection::DecorateCells(Decorator decorator) {
|
|
|
|
for (int y = y_min_; y <= y_max_; ++y) {
|
|
|
|
for (int x = x_min_; x <= x_max_; ++x) {
|
2022-03-31 08:17:43 +08:00
|
|
|
if (y % 2 == 1 && x % 2 == 1) {
|
2021-10-16 05:04:11 +08:00
|
|
|
Element& e = table_->elements_[y][x];
|
|
|
|
e = std::move(e) | decorator;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-31 08:17:43 +08:00
|
|
|
// NOLINTNEXTLINE
|
2021-10-16 05:04:11 +08:00
|
|
|
void TableSelection::DecorateAlternateColumn(Decorator decorator,
|
|
|
|
int modulo,
|
|
|
|
int shift) {
|
|
|
|
for (int y = y_min_; y <= y_max_; ++y) {
|
|
|
|
for (int x = x_min_; x <= x_max_; ++x) {
|
2022-03-31 08:17:43 +08:00
|
|
|
if (y % 2 == 1 && (x / 2) % modulo == shift) {
|
2021-10-16 05:04:11 +08:00
|
|
|
Element& e = table_->elements_[y][x];
|
|
|
|
e = std::move(e) | decorator;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-31 08:17:43 +08:00
|
|
|
// NOLINTNEXTLINE
|
2021-10-16 05:04:11 +08:00
|
|
|
void TableSelection::DecorateAlternateRow(Decorator decorator,
|
|
|
|
int modulo,
|
|
|
|
int shift) {
|
|
|
|
for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
|
|
|
|
for (int x = x_min_; x <= x_max_; ++x) {
|
2022-03-31 08:17:43 +08:00
|
|
|
if (y % 2 == 1 && (y / 2) % modulo == shift) {
|
2021-10-16 05:04:11 +08:00
|
|
|
Element& e = table_->elements_[y][x];
|
|
|
|
e = std::move(e) | decorator;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-31 08:17:43 +08:00
|
|
|
// NOLINTNEXTLINE
|
2021-10-16 05:04:11 +08:00
|
|
|
void TableSelection::DecorateCellsAlternateColumn(Decorator decorator,
|
|
|
|
int modulo,
|
|
|
|
int shift) {
|
|
|
|
for (int y = y_min_; y <= y_max_; ++y) {
|
|
|
|
for (int x = x_min_; x <= x_max_; ++x) {
|
2022-03-31 08:17:43 +08:00
|
|
|
if (y % 2 == 1 && x % 2 == 1 && ((x / 2) % modulo == shift)) {
|
2021-10-16 05:04:11 +08:00
|
|
|
Element& e = table_->elements_[y][x];
|
|
|
|
e = std::move(e) | decorator;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-31 08:17:43 +08:00
|
|
|
// NOLINTNEXTLINE
|
2021-10-16 05:04:11 +08:00
|
|
|
void TableSelection::DecorateCellsAlternateRow(Decorator decorator,
|
|
|
|
int modulo,
|
|
|
|
int shift) {
|
|
|
|
for (int y = y_min_; y <= y_max_; ++y) {
|
|
|
|
for (int x = x_min_; x <= x_max_; ++x) {
|
2022-03-31 08:17:43 +08:00
|
|
|
if (y % 2 == 1 && x % 2 == 1 && ((y / 2) % modulo == shift)) {
|
2021-10-16 05:04:11 +08:00
|
|
|
Element& e = table_->elements_[y][x];
|
|
|
|
e = std::move(e) | decorator;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-31 08:17:43 +08:00
|
|
|
void TableSelection::Border(BorderStyle border) {
|
|
|
|
BorderLeft(border);
|
|
|
|
BorderRight(border);
|
|
|
|
BorderTop(border);
|
|
|
|
BorderBottom(border);
|
|
|
|
|
|
|
|
// NOLINTNEXTLINE
|
|
|
|
table_->elements_[y_min_][x_min_] = text(charset[border][0]) | automerge;
|
|
|
|
// NOLINTNEXTLINE
|
|
|
|
table_->elements_[y_min_][x_max_] = text(charset[border][1]) | automerge;
|
|
|
|
// NOLINTNEXTLINE
|
|
|
|
table_->elements_[y_max_][x_min_] = text(charset[border][2]) | automerge;
|
|
|
|
// NOLINTNEXTLINE
|
|
|
|
table_->elements_[y_max_][x_max_] = text(charset[border][3]) | automerge;
|
2021-10-16 05:04:11 +08:00
|
|
|
}
|
|
|
|
|
2022-03-31 08:17:43 +08:00
|
|
|
void TableSelection::Separator(BorderStyle border) {
|
2021-10-16 05:04:11 +08:00
|
|
|
for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
|
|
|
|
for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
|
|
|
|
if (y % 2 == 0 || x % 2 == 0) {
|
|
|
|
Element& e = table_->elements_[y][x];
|
2022-03-31 08:17:43 +08:00
|
|
|
e = (y % 2 == 1)
|
|
|
|
? separatorCharacter(charset[border][5]) | automerge // NOLINT
|
|
|
|
: separatorCharacter(charset[border][4]) | automerge; // NOLINT
|
2021-10-16 05:04:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-31 08:17:43 +08:00
|
|
|
void TableSelection::SeparatorVertical(BorderStyle border) {
|
2021-10-16 05:04:11 +08:00
|
|
|
for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
|
|
|
|
for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
|
|
|
|
if (x % 2 == 0) {
|
2022-02-13 18:41:31 +08:00
|
|
|
table_->elements_[y][x] =
|
2022-03-31 08:17:43 +08:00
|
|
|
separatorCharacter(charset[border][5]) | automerge; // NOLINT
|
2021-10-16 05:04:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-31 08:17:43 +08:00
|
|
|
void TableSelection::SeparatorHorizontal(BorderStyle border) {
|
2021-10-16 05:04:11 +08:00
|
|
|
for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
|
|
|
|
for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
|
|
|
|
if (y % 2 == 0) {
|
2022-02-13 18:41:31 +08:00
|
|
|
table_->elements_[y][x] =
|
2022-03-31 08:17:43 +08:00
|
|
|
separatorCharacter(charset[border][4]) | automerge; // NOLINT
|
2021-10-16 05:04:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-31 08:17:43 +08:00
|
|
|
void TableSelection::BorderLeft(BorderStyle border) {
|
2022-02-13 18:41:31 +08:00
|
|
|
for (int y = y_min_; y <= y_max_; y++) {
|
|
|
|
table_->elements_[y][x_min_] =
|
2022-03-31 08:17:43 +08:00
|
|
|
separatorCharacter(charset[border][5]) | automerge; // NOLINT
|
2022-02-13 18:41:31 +08:00
|
|
|
}
|
2021-10-16 05:04:11 +08:00
|
|
|
}
|
|
|
|
|
2022-03-31 08:17:43 +08:00
|
|
|
void TableSelection::BorderRight(BorderStyle border) {
|
2022-02-13 18:41:31 +08:00
|
|
|
for (int y = y_min_; y <= y_max_; y++) {
|
|
|
|
table_->elements_[y][x_max_] =
|
2022-03-31 08:17:43 +08:00
|
|
|
separatorCharacter(charset[border][5]) | automerge; // NOLINT
|
2022-02-13 18:41:31 +08:00
|
|
|
}
|
2021-10-16 05:04:11 +08:00
|
|
|
}
|
|
|
|
|
2022-03-31 08:17:43 +08:00
|
|
|
void TableSelection::BorderTop(BorderStyle border) {
|
2022-02-13 18:41:31 +08:00
|
|
|
for (int x = x_min_; x <= x_max_; x++) {
|
|
|
|
table_->elements_[y_min_][x] =
|
2022-03-31 08:17:43 +08:00
|
|
|
separatorCharacter(charset[border][4]) | automerge; // NOLINT
|
2022-02-13 18:41:31 +08:00
|
|
|
}
|
2021-10-16 05:04:11 +08:00
|
|
|
}
|
|
|
|
|
2022-03-31 08:17:43 +08:00
|
|
|
void TableSelection::BorderBottom(BorderStyle border) {
|
2022-02-13 18:41:31 +08:00
|
|
|
for (int x = x_min_; x <= x_max_; x++) {
|
|
|
|
table_->elements_[y_max_][x] =
|
2022-03-31 08:17:43 +08:00
|
|
|
separatorCharacter(charset[border][4]) | automerge; // NOLINT
|
2022-02-13 18:41:31 +08:00
|
|
|
}
|
2021-10-16 05:04:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace ftxui
|
|
|
|
|
|
|
|
// Copyright 2021 Arthur Sonzogni. All rights reserved.
|
|
|
|
// Use of this source code is governed by the MIT license that can be found in
|
|
|
|
// the LICENSE file.
|