-
-
Notifications
You must be signed in to change notification settings - Fork 577
Expand file tree
/
Copy pathtable.cpp
More file actions
437 lines (390 loc) · 13.8 KB
/
table.cpp
File metadata and controls
437 lines (390 loc) · 13.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
// 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.
#include "ftxui/dom/table.hpp"
#include <algorithm> // for max
#include <initializer_list> // for initializer_list
#include <memory> // for allocator, shared_ptr, allocator_traits<>::value_type
#include <utility> // for move, swap
#include <vector> // for vector
#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;
}
// NOLINTNEXTLINE
static std::string charset[6][6] = {
{"┌", "┐", "└", "┘", "─", "│"}, // LIGHT
{"┏", "┓", "┗", "┛", "╍", "╏"}, // DASHED
{"┏", "┓", "┗", "┛", "━", "┃"}, // HEAVY
{"╔", "╗", "╚", "╝", "═", "║"}, // DOUBLE
{"╭", "╮", "╰", "╯", "─", "│"}, // ROUNDED
{" ", " ", " ", " ", " ", " "}, // EMPTY
};
int Wrap(int input, int modulo) {
input %= modulo;
input += modulo;
input %= modulo;
return input;
}
void Order(int& a, int& b) {
if (a >= b) {
std::swap(a, b);
}
}
} // namespace
/// @brief Create an empty table.
Table::Table() {
Initialize({});
}
/// @brief Create a table from a vector of vector of string.
/// @param input The input data.
Table::Table(std::vector<std::vector<std::string>> input) {
std::vector<std::vector<Element>> output;
output.reserve(input.size());
for (auto& row : input) {
output.emplace_back();
auto& output_row = output.back();
output_row.reserve(row.size());
for (auto& cell : row) {
output_row.push_back(text(std::move(cell)));
}
}
Initialize(std::move(output));
}
/// @brief Create a table from a vector of vector of Element
/// @param input The input elements.
Table::Table(std::vector<std::vector<Element>> input) {
Initialize(std::move(input));
}
// @brief Create a table from a list of list of string.
// @param init The input data.
Table::Table(std::initializer_list<std::vector<std::string>> init) {
std::vector<std::vector<Element>> input;
for (const auto& row : init) {
std::vector<Element> output_row;
output_row.reserve(row.size());
for (const auto& cell : row) {
output_row.push_back(text(cell));
}
input.push_back(std::move(output_row));
}
Initialize(std::move(input));
}
// private
void Table::Initialize(std::vector<std::vector<Element>> input) {
input_dim_y_ = static_cast<int>(input.size());
input_dim_x_ = 0;
for (auto& row : input) {
input_dim_x_ = std::max(input_dim_x_, int(row.size()));
}
dim_y_ = 2 * input_dim_y_ + 1;
dim_x_ = 2 * input_dim_x_ + 1;
// Reserve space.
elements_.resize(dim_y_);
for (int y = 0; y < dim_y_; ++y) {
elements_[y].resize(dim_x_);
}
// Transfert elements_ from |input| toward |elements_|.
{
int y = 1;
for (auto& row : input) {
int x = 1;
for (auto& cell : row) {
elements_[y][x] = std::move(cell);
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)) {
if (!element) {
element = emptyElement();
}
continue;
}
element = emptyElement();
}
}
}
/// @brief Select a row of the table.
/// @param index The index of the row to select.
/// @note You can use negative index to select from the end.
TableSelection Table::SelectRow(int index) {
return SelectRectangle(0, -1, index, index);
}
/// @brief Select a range of rows of the table.
/// @param row_min The first row to select.
/// @param row_max The last row to select.
/// @note You can use negative index to select from the end.
TableSelection Table::SelectRows(int row_min, int row_max) {
return SelectRectangle(0, -1, row_min, row_max);
}
/// @brief Select a column of the table.
/// @param index The index of the column to select.
/// @note You can use negative index to select from the end.
TableSelection Table::SelectColumn(int index) {
return SelectRectangle(index, index, 0, -1);
}
/// @brief Select a range of columns of the table.
/// @param column_min The first column to select.
/// @param column_max The last column to select.
/// @note You can use negative index to select from the end.
TableSelection Table::SelectColumns(int column_min, int column_max) {
return SelectRectangle(column_min, column_max, 0, -1);
}
/// @brief Select a cell of the table.
/// @param column The column of the cell to select.
/// @param row The row of the cell to select.
/// @note You can use negative index to select from the end.
TableSelection Table::SelectCell(int column, int row) {
return SelectRectangle(column, column, row, row);
}
/// @brief Select a rectangle of the table.
/// @param column_min The first column to select.
/// @param column_max The last column to select.
/// @param row_min The first row to select.
/// @param row_max The last row to select.
/// @note You can use negative index to select from the end.
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);
TableSelection output; // NOLINT
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;
}
/// @brief Select all the table.
TableSelection Table::SelectAll() {
TableSelection output; // NOLINT
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;
}
/// @brief Render the table.
/// @return The rendered table. This is an element you can draw.
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; //it = std::move(it); // | flex;
continue;
}
// Cells
if ((x % 2) == 1 && (y % 2) == 1) {
// it = std::move(it) | flex_shrink; //it = std::move(it) | flex_shrink;
continue;
}
// Corners
it = std::move(it) | size(WIDTH, EQUAL, 0) | size(HEIGHT, EQUAL, 0);
}
}
dim_x_ = 0;
dim_y_ = 0;
return gridbox(std::move(elements_));
}
/// @brief Apply the `decorator` to the selection.
/// This decorate both the cells, the lines and the corners.
/// @param decorator The decorator to apply.
// NOLINTNEXTLINE
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;
}
}
}
/// @brief Apply the `decorator` to the selection.
/// @param decorator The decorator to apply.
/// This decorate only the cells.
// NOLINTNEXTLINE
void TableSelection::DecorateCells(Decorator decorator) {
for (int y = y_min_; y <= y_max_; ++y) {
for (int x = x_min_; x <= x_max_; ++x) {
if (y % 2 == 1 && x % 2 == 1) {
Element& e = table_->elements_[y][x];
e = std::move(e) | decorator;
}
}
}
}
/// @brief Apply the `decorator` to the selection.
/// This decorate only the lines modulo `modulo` with a shift of `shift`.
/// @param decorator The decorator to apply.
/// @param modulo The modulo of the lines to decorate.
/// @param shift The shift of the lines to decorate.
// NOLINTNEXTLINE
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) {
if (y % 2 == 1 && (x / 2) % modulo == shift) {
Element& e = table_->elements_[y][x];
e = std::move(e) | decorator;
}
}
}
}
/// @brief Apply the `decorator` to the selection.
/// This decorate only the lines modulo `modulo` with a shift of `shift`.
/// @param decorator The decorator to apply.
/// @param modulo The modulo of the lines to decorate.
/// @param shift The shift of the lines to decorate.
// NOLINTNEXTLINE
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) {
if (y % 2 == 1 && (y / 2) % modulo == shift) {
Element& e = table_->elements_[y][x];
e = std::move(e) | decorator;
}
}
}
}
/// @brief Apply the `decorator` to the selection.
/// This decorate only the corners modulo `modulo` with a shift of `shift`.
/// @param decorator The decorator to apply.
/// @param modulo The modulo of the corners to decorate.
/// @param shift The shift of the corners to decorate.
// NOLINTNEXTLINE
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) {
if (y % 2 == 1 && x % 2 == 1 && ((x / 2) % modulo == shift)) {
Element& e = table_->elements_[y][x];
e = std::move(e) | decorator;
}
}
}
}
/// @brief Apply the `decorator` to the selection.
/// This decorate only the corners modulo `modulo` with a shift of `shift`.
/// @param decorator The decorator to apply.
/// @param modulo The modulo of the corners to decorate.
/// @param shift The shift of the corners to decorate.
// NOLINTNEXTLINE
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) {
if (y % 2 == 1 && x % 2 == 1 && ((y / 2) % modulo == shift)) {
Element& e = table_->elements_[y][x];
e = std::move(e) | decorator;
}
}
}
}
/// @brief Apply a `border` around the selection.
/// @param border The border style to apply.
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;
}
/// @brief Draw some separator lines in the selection.
/// @param border The border style to apply.
void TableSelection::Separator(BorderStyle border) {
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];
e = (y % 2 == 1)
? separatorCharacter(charset[border][5]) | automerge // NOLINT
: separatorCharacter(charset[border][4]) | automerge; // NOLINT
}
}
}
}
/// @brief Draw some vertical separator lines in the selection.
/// @param border The border style to apply.
void TableSelection::SeparatorVertical(BorderStyle border) {
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) {
table_->elements_[y][x] =
separatorCharacter(charset[border][5]) | automerge; // NOLINT
}
}
}
}
/// @brief Draw some horizontal separator lines in the selection.
/// @param border The border style to apply.
void TableSelection::SeparatorHorizontal(BorderStyle border) {
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) {
table_->elements_[y][x] =
separatorCharacter(charset[border][4]) | automerge; // NOLINT
}
}
}
}
/// @brief Draw some separator lines to the left side of the selection.
/// @param border The border style to apply.
void TableSelection::BorderLeft(BorderStyle border) {
for (int y = y_min_; y <= y_max_; y++) {
table_->elements_[y][x_min_] =
separatorCharacter(charset[border][5]) | automerge; // NOLINT
}
}
/// @brief Draw some separator lines to the right side of the selection.
/// @param border The border style to apply.
void TableSelection::BorderRight(BorderStyle border) {
for (int y = y_min_; y <= y_max_; y++) {
table_->elements_[y][x_max_] =
separatorCharacter(charset[border][5]) | automerge; // NOLINT
}
}
/// @brief Draw some separator lines to the top side of the selection.
/// @param border The border style to apply.
void TableSelection::BorderTop(BorderStyle border) {
for (int x = x_min_; x <= x_max_; x++) {
table_->elements_[y_min_][x] =
separatorCharacter(charset[border][4]) | automerge; // NOLINT
}
}
/// @brief Draw some separator lines to the bottom side of the selection.
/// @param border The border style to apply.
void TableSelection::BorderBottom(BorderStyle border) {
for (int x = x_min_; x <= x_max_; x++) {
table_->elements_[y_max_][x] =
separatorCharacter(charset[border][4]) | automerge; // NOLINT
}
}
} // namespace ftxui