7#include <initializer_list>
17bool IsCell(
int x,
int y) {
18 return x % 2 == 1 && y % 2 == 1;
22static std::string charset[6][6] = {
23 {
"┌",
"┐",
"└",
"┘",
"─",
"│"},
24 {
"┏",
"┓",
"┗",
"┛",
"╍",
"╏"},
25 {
"┏",
"┓",
"┗",
"┛",
"━",
"┃"},
26 {
"╔",
"╗",
"╚",
"╝",
"═",
"║"},
27 {
"╭",
"╮",
"╰",
"╯",
"─",
"│"},
28 {
" ",
" ",
" ",
" ",
" ",
" "},
38void Order(
int& a,
int& b) {
54 std::vector<std::vector<Element>> output;
55 output.reserve(
input.size());
56 for (
auto& row :
input) {
57 output.emplace_back();
58 auto& output_row = output.back();
59 output_row.reserve(row.size());
60 for (
auto& cell : row) {
61 output_row.push_back(
text(std::move(cell)));
64 Initialize(std::move(output));
70 Initialize(std::move(
input));
75Table::Table(std::initializer_list<std::vector<std::string>> init) {
76 std::vector<std::vector<Element>>
input;
77 for (
const auto& row : init) {
78 std::vector<Element> output_row;
79 output_row.reserve(row.size());
80 for (
const auto& cell : row) {
81 output_row.push_back(
text(cell));
83 input.push_back(std::move(output_row));
85 Initialize(std::move(
input));
89void Table::Initialize(std::vector<std::vector<Element>>
input) {
90 input_dim_y_ =
static_cast<int>(
input.size());
92 for (
auto& row :
input) {
93 input_dim_x_ = std::max(input_dim_x_,
int(row.size()));
96 dim_y_ = 2 * input_dim_y_ + 1;
97 dim_x_ = 2 * input_dim_x_ + 1;
100 elements_.resize(dim_y_);
101 for (
int y = 0; y < dim_y_; ++y) {
102 elements_[y].resize(dim_x_);
108 for (
auto& row :
input) {
110 for (
auto& cell : row) {
111 elements_[y][x] = std::move(cell);
119 for (
int y = 0; y < dim_y_; ++y) {
120 for (
int x = 0; x < dim_x_; ++x) {
121 auto& element = elements_[y][x];
183 column_min =
Wrap(column_min, input_dim_x_);
184 column_max =
Wrap(column_max, input_dim_x_);
185 Order(column_min, column_max);
186 row_min =
Wrap(row_min, input_dim_y_);
187 row_max =
Wrap(row_max, input_dim_y_);
188 Order(row_min, row_max);
191 output.table_ =
this;
192 output.x_min_ = 2 * column_min;
193 output.x_max_ = 2 * column_max + 2;
194 output.y_min_ = 2 * row_min;
195 output.y_max_ = 2 * row_max + 2;
202 output.table_ =
this;
204 output.x_max_ = dim_x_ - 1;
206 output.y_max_ = dim_y_ - 1;
213 for (
int y = 0; y < dim_y_; ++y) {
214 for (
int x = 0; x < dim_x_; ++x) {
215 auto& it = elements_[y][x];
218 if ((x + y) % 2 == 1) {
219 it = std::move(it) |
flex;
224 if ((x % 2) == 1 && (y % 2) == 1) {
235 return gridbox(std::move(elements_));
243 for (
int y = y_min_; y <= y_max_; ++y) {
244 for (
int x = x_min_; x <= x_max_; ++x) {
245 Element& e = table_->elements_[y][x];
246 e = std::move(e) | decorator;
256 for (
int y = y_min_; y <= y_max_; ++y) {
257 for (
int x = x_min_; x <= x_max_; ++x) {
258 if (y % 2 == 1 && x % 2 == 1) {
259 Element& e = table_->elements_[y][x];
260 e = std::move(e) | decorator;
275 for (
int y = y_min_; y <= y_max_; ++y) {
276 for (
int x = x_min_; x <= x_max_; ++x) {
277 if (y % 2 == 1 && (x / 2) % modulo == shift) {
278 Element& e = table_->elements_[y][x];
279 e = std::move(e) | decorator;
294 for (
int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
295 for (
int x = x_min_; x <= x_max_; ++x) {
296 if (y % 2 == 1 && (y / 2) % modulo == shift) {
297 Element& e = table_->elements_[y][x];
298 e = std::move(e) | decorator;
313 for (
int y = y_min_; y <= y_max_; ++y) {
314 for (
int x = x_min_; x <= x_max_; ++x) {
315 if (y % 2 == 1 && x % 2 == 1 && ((x / 2) % modulo == shift)) {
316 Element& e = table_->elements_[y][x];
317 e = std::move(e) | decorator;
332 for (
int y = y_min_; y <= y_max_; ++y) {
333 for (
int x = x_min_; x <= x_max_; ++x) {
334 if (y % 2 == 1 && x % 2 == 1 && ((y / 2) % modulo == shift)) {
335 Element& e = table_->elements_[y][x];
336 e = std::move(e) | decorator;
351 table_->elements_[y_min_][x_min_] =
text(charset[border][0]) |
automerge;
353 table_->elements_[y_min_][x_max_] =
text(charset[border][1]) |
automerge;
355 table_->elements_[y_max_][x_min_] =
text(charset[border][2]) |
automerge;
357 table_->elements_[y_max_][x_max_] =
text(charset[border][3]) |
automerge;
363 for (
int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
364 for (
int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
365 if (y % 2 == 0 || x % 2 == 0) {
366 Element& e = table_->elements_[y][x];
378 for (
int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
379 for (
int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
381 table_->elements_[y][x] =
391 for (
int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
392 for (
int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
394 table_->elements_[y][x] =
404 for (
int y = y_min_; y <= y_max_; y++) {
405 table_->elements_[y][x_min_] =
413 for (
int y = y_min_; y <= y_max_; y++) {
414 table_->elements_[y][x_max_] =
422 for (
int x = x_min_; x <= x_max_; x++) {
423 table_->elements_[y_min_][x] =
431 for (
int x = x_min_; x <= x_max_; x++) {
432 table_->elements_[y_max_][x] =
void DecorateAlternateColumn(Decorator, int modulo=2, int shift=0)
將 decorator 應用於選取範圍。 這只會裝飾模數為 modulo,偏移量為 shift 的線條。
void SeparatorVertical(BorderStyle border=LIGHT)
在選取範圍內繪製一些垂直分隔線。
void DecorateCells(Decorator)
將 decorator 應用於選取範圍。 這只會裝飾單元格。
void BorderLeft(BorderStyle border=LIGHT)
在選取範圍的左側繪製一些分隔線。
void DecorateCellsAlternateColumn(Decorator, int modulo=2, int shift=0)
將 decorator 應用於選取範圍。 這只會裝飾模數為 modulo,偏移量為 shift 的角落。
void Decorate(Decorator)
將 decorator 應用於選取範圍。 這會裝飾單元格、線條和角落。
void DecorateAlternateRow(Decorator, int modulo=2, int shift=0)
將 decorator 應用於選取範圍。 這只會裝飾模數為 modulo,偏移量為 shift 的線條。
void BorderTop(BorderStyle border=LIGHT)
在選取範圍的頂部繪製一些分隔線。
void Separator(BorderStyle border=LIGHT)
在選取範圍內繪製一些分隔線。
void BorderBottom(BorderStyle border=LIGHT)
在選取範圍的底部繪製一些分隔線。
void DecorateCellsAlternateRow(Decorator, int modulo=2, int shift=0)
將 decorator 應用於選取範圍。 這只會裝飾模數為 modulo,偏移量為 shift 的角落。
void BorderRight(BorderStyle border=LIGHT)
在選取範圍的右側繪製一些分隔線。
void Border(BorderStyle border=LIGHT)
在選取範圍周圍應用 border。
void SeparatorHorizontal(BorderStyle border=LIGHT)
在選取範圍內繪製一些水平分隔線。
Component Wrap(std::string name, Component component)
TableSelection SelectCell(int column, int row)
選取表格的一個單元格。
TableSelection SelectColumn(int column_index)
選取表格的某一列。
TableSelection SelectRow(int row_index)
選取表格的某一行。
TableSelection SelectColumns(int column_min, int column_max)
選取表格的列範圍。
TableSelection SelectRows(int row_min, int row_max)
選取表格的行範圍。
TableSelection SelectAll()
選取整個表格。
TableSelection SelectRectangle(int column_min, int column_max, int row_min, int row_max)
選取表格的一個矩形區域。
Decorator size(WidthOrHeight, Constraint, int value)
限制元素的大小。
Element flex(Element)
使子元素按比例擴展以佔據容器中剩餘的空間。
Element flex_shrink(Element)
在需要時最小化。
Element text(std::wstring text)
顯示一段 Unicode 文字。
Element separatorCharacter(std::string)
在兩個元素之間繪製垂直或水平分隔線。
Element automerge(Element child)
啟用字符自動與附近其他字符合併。
BorderStyle
BorderStyle 是一個列舉,表示可以應用於終端機 UI 元素的不同邊框樣式。
std::function< Element(Element)> Decorator
std::shared_ptr< Node > Element
Element gridbox(std::vector< Elements > lines)
顯示元素網格的容器。