FTXUI 6.1.9
C++ functional terminal UI.
Loading...
Searching...
No Matches
src/ftxui/dom/table.cpp
Go to the documentation of this file.
1// Copyright 2021 Arthur Sonzogni. All rights reserved.
2// Use of this source code is governed by the MIT license that can be found in
3// the LICENSE file.
4#include "ftxui/dom/table.hpp"
5
6#include <algorithm> // for max
7#include <initializer_list> // for initializer_list
8#include <memory> // for allocator, shared_ptr, allocator_traits<>::value_type
9#include <utility> // for move, swap
10#include <vector> // for vector
11
12#include "ftxui/dom/elements.hpp" // for Element, operator|, text, separatorCharacter, Elements, BorderStyle, Decorator, emptyElement, size, gridbox, EQUAL, flex, flex_shrink, HEIGHT, WIDTH
13
14namespace ftxui {
15namespace {
16
17bool IsCell(int x, int y) {
18 return x % 2 == 1 && y % 2 == 1;
19}
20
21// NOLINTNEXTLINE
22static std::string charset[6][6] = {
23 {"┌", "┐", "└", "┘", "─", "│"}, // LIGHT
24 {"┏", "┓", "┗", "┛", "╍", "╏"}, // DASHED
25 {"┏", "┓", "┗", "┛", "━", "┃"}, // HEAVY
26 {"╔", "╗", "╚", "╝", "═", "║"}, // DOUBLE
27 {"╭", "╮", "╰", "╯", "─", "│"}, // ROUNDED
28 {" ", " ", " ", " ", " ", " "}, // EMPTY
29};
30
31int Wrap(int input, int modulo) {
32 input %= modulo;
33 input += modulo;
34 input %= modulo;
35 return input;
36}
37
38void Order(int& a, int& b) {
39 if (a >= b) {
40 std::swap(a, b);
41 }
42}
43
44} // namespace
45
46/// @brief Create an empty table.
48 Initialize({});
49}
50
51/// @brief Create a table from a vector of vector of string.
52/// @param input The input data.
53Table::Table(std::vector<std::vector<std::string>> input) {
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)));
62 }
63 }
64 Initialize(std::move(output));
65}
66
67/// @brief Create a table from a vector of vector of Element
68/// @param input The input elements.
69Table::Table(std::vector<std::vector<Element>> input) {
70 Initialize(std::move(input));
71}
72
73/// @brief Create a table from a list of list of string.
74/// @param init The input data.
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));
82 }
83 input.push_back(std::move(output_row));
84 }
85 Initialize(std::move(input));
86}
87
88// private
89void Table::Initialize(std::vector<std::vector<Element>> input) {
90 input_dim_y_ = static_cast<int>(input.size());
91 input_dim_x_ = 0;
92 for (auto& row : input) {
93 input_dim_x_ = std::max(input_dim_x_, int(row.size()));
94 }
95
96 dim_y_ = 2 * input_dim_y_ + 1;
97 dim_x_ = 2 * input_dim_x_ + 1;
98
99 // Reserve space.
100 elements_.resize(dim_y_);
101 for (int y = 0; y < dim_y_; ++y) {
102 elements_[y].resize(dim_x_);
103 }
104
105 // Transfert elements_ from |input| toward |elements_|.
106 {
107 int y = 1;
108 for (auto& row : input) {
109 int x = 1;
110 for (auto& cell : row) {
111 elements_[y][x] = std::move(cell);
112 x += 2;
113 }
114 y += 2;
115 }
116 }
117
118 // Add empty element for the border.
119 for (int y = 0; y < dim_y_; ++y) {
120 for (int x = 0; x < dim_x_; ++x) {
121 auto& element = elements_[y][x];
122
123 if (IsCell(x, y)) {
124 if (!element) {
125 element = emptyElement();
126 }
127 continue;
128 }
129
130 element = emptyElement();
131 }
132 }
133}
134
135/// @brief Select a row of the table.
136/// @param index The index of the row to select.
137/// @note You can use negative index to select from the end.
139 return SelectRectangle(0, -1, index, index);
140}
141
142/// @brief Select a range of rows of the table.
143/// @param row_min The first row to select.
144/// @param row_max The last row to select.
145/// @note You can use negative index to select from the end.
146TableSelection Table::SelectRows(int row_min, int row_max) {
147 return SelectRectangle(0, -1, row_min, row_max);
148}
149
150/// @brief Select a column of the table.
151/// @param index The index of the column to select.
152/// @note You can use negative index to select from the end.
154 return SelectRectangle(index, index, 0, -1);
155}
156
157/// @brief Select a range of columns of the table.
158/// @param column_min The first column to select.
159/// @param column_max The last column to select.
160/// @note You can use negative index to select from the end.
161TableSelection Table::SelectColumns(int column_min, int column_max) {
162 return SelectRectangle(column_min, column_max, 0, -1);
163}
164
165/// @brief Select a cell of the table.
166/// @param column The column of the cell to select.
167/// @param row The row of the cell to select.
168/// @note You can use negative index to select from the end.
169TableSelection Table::SelectCell(int column, int row) {
170 return SelectRectangle(column, column, row, row);
171}
172
173/// @brief Select a rectangle of the table.
174/// @param column_min The first column to select.
175/// @param column_max The last column to select.
176/// @param row_min The first row to select.
177/// @param row_max The last row to select.
178/// @note You can use negative index to select from the end.
180 int column_max,
181 int row_min,
182 int row_max) {
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);
189
190 TableSelection output; // NOLINT
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;
196 return output;
197}
198
199/// @brief Select all the table.
201 TableSelection output; // NOLINT
202 output.table_ = this;
203 output.x_min_ = 0;
204 output.x_max_ = dim_x_ - 1;
205 output.y_min_ = 0;
206 output.y_max_ = dim_y_ - 1;
207 return output;
208}
209
210/// @brief Render the table.
211/// @return The rendered table. This is an element you can draw.
213 for (int y = 0; y < dim_y_; ++y) {
214 for (int x = 0; x < dim_x_; ++x) {
215 auto& it = elements_[y][x];
216
217 // Line
218 if ((x + y) % 2 == 1) {
219 it = std::move(it) | flex;
220 continue;
221 }
222
223 // Cells
224 if ((x % 2) == 1 && (y % 2) == 1) {
225 it = std::move(it) | flex_shrink;
226 continue;
227 }
228
229 // Corners
230 it = std::move(it) | size(WIDTH, EQUAL, 0) | size(HEIGHT, EQUAL, 0);
231 }
232 }
233 dim_x_ = 0;
234 dim_y_ = 0;
235 return gridbox(std::move(elements_));
236}
237
238/// @brief Apply the `decorator` to the selection.
239/// This decorate both the cells, the lines and the corners.
240/// @param decorator The decorator to apply.
241// NOLINTNEXTLINE
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;
247 }
248 }
249}
250
251/// @brief Apply the `decorator` to the selection.
252/// @param decorator The decorator to apply.
253/// This decorate only the cells.
254// NOLINTNEXTLINE
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;
261 }
262 }
263 }
264}
265
266/// @brief Apply the `decorator` to the selection.
267/// This decorate only the lines modulo `modulo` with a shift of `shift`.
268/// @param decorator The decorator to apply.
269/// @param modulo The modulo of the lines to decorate.
270/// @param shift The shift of the lines to decorate.
271// NOLINTNEXTLINE
273 int modulo,
274 int shift) {
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;
280 }
281 }
282 }
283}
284
285/// @brief Apply the `decorator` to the selection.
286/// This decorate only the lines modulo `modulo` with a shift of `shift`.
287/// @param decorator The decorator to apply.
288/// @param modulo The modulo of the lines to decorate.
289/// @param shift The shift of the lines to decorate.
290// NOLINTNEXTLINE
292 int modulo,
293 int shift) {
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;
299 }
300 }
301 }
302}
303
304/// @brief Apply the `decorator` to the selection.
305/// This decorate only the corners modulo `modulo` with a shift of `shift`.
306/// @param decorator The decorator to apply.
307/// @param modulo The modulo of the corners to decorate.
308/// @param shift The shift of the corners to decorate.
309// NOLINTNEXTLINE
311 int modulo,
312 int shift) {
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;
318 }
319 }
320 }
321}
322
323/// @brief Apply the `decorator` to the selection.
324/// This decorate only the corners modulo `modulo` with a shift of `shift`.
325/// @param decorator The decorator to apply.
326/// @param modulo The modulo of the corners to decorate.
327/// @param shift The shift of the corners to decorate.
328// NOLINTNEXTLINE
330 int modulo,
331 int shift) {
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;
337 }
338 }
339 }
340}
341
342/// @brief Apply the `decorator` to the border of the selection.
343/// @param decorator The decorator to apply.
345 for (int x = x_min_; x <= x_max_; ++x) {
346 table_->elements_[y_min_][x] =
347 std::move(table_->elements_[y_min_][x]) | decorator;
348 table_->elements_[y_max_][x] =
349 std::move(table_->elements_[y_max_][x]) | decorator;
350 }
351 for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
352 table_->elements_[y][x_min_] =
353 std::move(table_->elements_[y][x_min_]) | decorator;
354 table_->elements_[y][x_max_] =
355 std::move(table_->elements_[y][x_max_]) | decorator;
356 }
357}
358
359/// @brief Apply the `decorator` to the left border of the selection.
360/// @param decorator The decorator to apply.
362 for (int y = y_min_; y <= y_max_; y++) {
363 table_->elements_[y][x_min_] =
364 std::move(table_->elements_[y][x_min_]) | decorator;
365 }
366}
367
368/// @brief Apply the `decorator` to the right border of the selection.
369/// @param decorator The decorator to apply.
371 for (int y = y_min_; y <= y_max_; y++) {
372 table_->elements_[y][x_max_] =
373 std::move(table_->elements_[y][x_max_]) | decorator;
374 }
375}
376
377/// @brief Apply the `decorator` to the top border of the selection.
378/// @param decorator The decorator to apply.
380 for (int x = x_min_; x <= x_max_; x++) {
381 table_->elements_[y_min_][x] =
382 std::move(table_->elements_[y_min_][x]) | decorator;
383 }
384}
385
386/// @brief Apply the `decorator` to the bottom border of the selection.
387/// @param decorator The decorator to apply.
389 for (int x = x_min_; x <= x_max_; x++) {
390 table_->elements_[y_max_][x] =
391 std::move(table_->elements_[y_max_][x]) | decorator;
392 }
393}
394
395/// @brief Apply the `decorator` to the separators of the selection.
396/// @param decorator The decorator to apply.
398 for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
399 for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
400 if (y % 2 == 0 || x % 2 == 0) {
401 table_->elements_[y][x] =
402 std::move(table_->elements_[y][x]) | decorator;
403 }
404 }
405 }
406}
407
408/// @brief Apply the `decorator` to the vertical separators of the selection.
409/// @param decorator The decorator to apply.
411 for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
412 for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
413 if (x % 2 == 0) {
414 table_->elements_[y][x] =
415 std::move(table_->elements_[y][x]) | decorator;
416 }
417 }
418 }
419}
420
421/// @brief Apply the `decorator` to the horizontal separators of the selection.
422/// @param decorator The decorator to apply.
424 for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
425 for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
426 if (y % 2 == 0) {
427 table_->elements_[y][x] =
428 std::move(table_->elements_[y][x]) | decorator;
429 }
430 }
431 }
432}
433
434/// @brief Apply a `border` around the selection.
435/// @param border The border style to apply.
437 BorderLeft(border);
438 BorderRight(border);
439 BorderTop(border);
440 BorderBottom(border);
441
442 // NOLINTNEXTLINE
443 table_->elements_[y_min_][x_min_] = text(charset[border][0]) | automerge;
444 // NOLINTNEXTLINE
445 table_->elements_[y_min_][x_max_] = text(charset[border][1]) | automerge;
446 // NOLINTNEXTLINE
447 table_->elements_[y_max_][x_min_] = text(charset[border][2]) | automerge;
448 // NOLINTNEXTLINE
449 table_->elements_[y_max_][x_max_] = text(charset[border][3]) | automerge;
450}
451
452/// @brief Apply a `border` around the selection.
453/// @param border The border style to apply.
454/// @param decorator The decorator to apply.
456 Border(border);
457 DecorateBorder(std::move(decorator));
458}
459
460/// @brief Draw some separator lines in the selection.
461/// @param border The border style to apply.
463 for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
464 for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
465 if (y % 2 == 0 || x % 2 == 0) {
466 Element& e = table_->elements_[y][x];
467 e = (y % 2 == 1)
468 ? separatorCharacter(charset[border][5]) | automerge // NOLINT
469 : separatorCharacter(charset[border][4]) | automerge; // NOLINT
470 }
471 }
472 }
473}
474
475/// @brief Draw some separator lines in the selection.
476/// @param border The border style to apply.
477/// @param decorator The decorator to apply.
479 Separator(border);
480 DecorateSeparator(std::move(decorator));
481}
482
483/// @brief Draw some vertical separator lines in the selection.
484/// @param border The border style to apply.
486 for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
487 for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
488 if (x % 2 == 0) {
489 table_->elements_[y][x] =
490 separatorCharacter(charset[border][5]) | automerge; // NOLINT
491 }
492 }
493 }
494}
495
496/// @brief Draw some vertical separator lines in the selection.
497/// @param border The border style to apply.
498/// @param decorator The decorator to apply.
500 Decorator decorator) {
501 SeparatorVertical(border);
502 DecorateSeparatorVertical(std::move(decorator));
503}
504
505/// @brief Draw some horizontal separator lines in the selection.
506/// @param border The border style to apply.
508 for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
509 for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
510 if (y % 2 == 0) {
511 table_->elements_[y][x] =
512 separatorCharacter(charset[border][4]) | automerge; // NOLINT
513 }
514 }
515 }
516}
517
518/// @brief Draw some horizontal separator lines in the selection.
519/// @param border The border style to apply.
520/// @param decorator The decorator to apply.
522 Decorator decorator) {
523 SeparatorHorizontal(border);
524 DecorateSeparatorHorizontal(std::move(decorator));
525}
526
527/// @brief Draw some separator lines to the left side of the selection.
528/// @param border The border style to apply.
530 for (int y = y_min_; y <= y_max_; y++) {
531 table_->elements_[y][x_min_] =
532 separatorCharacter(charset[border][5]) | automerge; // NOLINT
533 }
534}
535
536/// @brief Draw some separator lines to the left side of the selection.
537/// @param border The border style to apply.
538/// @param decorator The decorator to apply.
540 BorderLeft(border);
541 DecorateBorderLeft(std::move(decorator));
542}
543
544/// @brief Draw some separator lines to the right side of the selection.
545/// @param border The border style to apply.
547 for (int y = y_min_; y <= y_max_; y++) {
548 table_->elements_[y][x_max_] =
549 separatorCharacter(charset[border][5]) | automerge; // NOLINT
550 }
551}
552
553/// @brief Draw some separator lines to the right side of the selection.
554/// @param border The border style to apply.
555/// @param decorator The decorator to apply.
557 BorderRight(border);
558 DecorateBorderRight(std::move(decorator));
559}
560
561/// @brief Draw some separator lines to the top side of the selection.
562/// @param border The border style to apply.
564 for (int x = x_min_; x <= x_max_; x++) {
565 table_->elements_[y_min_][x] =
566 separatorCharacter(charset[border][4]) | automerge; // NOLINT
567 }
568}
569
570/// @brief Draw some separator lines to the top side of the selection.
571/// @param border The border style to apply.
572/// @param decorator The decorator to apply.
574 BorderTop(border);
575 DecorateBorderTop(std::move(decorator));
576}
577
578/// @brief Draw some separator lines to the bottom side of the selection.
579/// @param border The border style to apply.
581 for (int x = x_min_; x <= x_max_; x++) {
582 table_->elements_[y_max_][x] =
583 separatorCharacter(charset[border][4]) | automerge; // NOLINT
584 }
585}
586
587/// @brief Draw some separator lines to the bottom side of the selection.
588/// @param border The border style to apply.
589/// @param decorator The decorator to apply.
591 BorderBottom(border);
592 DecorateBorderBottom(std::move(decorator));
593}
594
595} // namespace ftxui
void DecorateAlternateColumn(Decorator, int modulo=2, int shift=0)
Apply the decorator to the selection. This decorate only the lines modulo modulo with a shift of shif...
void DecorateSeparatorHorizontal(Decorator)
Apply the decorator to the horizontal separators of the selection.
void DecorateBorderBottom(Decorator)
Apply the decorator to the bottom border of the selection.
void DecorateSeparator(Decorator)
Apply the decorator to the separators of the selection.
void SeparatorVertical(BorderStyle border=LIGHT)
Draw some vertical separator lines in the selection.
void DecorateCells(Decorator)
Apply the decorator to the selection.
void DecorateBorderRight(Decorator)
Apply the decorator to the right border of the selection.
void DecorateBorder(Decorator)
Apply the decorator to the border of the selection.
void BorderLeft(BorderStyle border=LIGHT)
Draw some separator lines to the left side of the selection.
void DecorateCellsAlternateColumn(Decorator, int modulo=2, int shift=0)
Apply the decorator to the selection. This decorate only the corners modulo modulo with a shift of sh...
void DecorateBorderLeft(Decorator)
Apply the decorator to the left border of the selection.
void Decorate(Decorator)
Apply the decorator to the selection. This decorate both the cells, the lines and the corners.
void DecorateAlternateRow(Decorator, int modulo=2, int shift=0)
Apply the decorator to the selection. This decorate only the lines modulo modulo with a shift of shif...
void BorderTop(BorderStyle border=LIGHT)
Draw some separator lines to the top side of the selection.
void Separator(BorderStyle border=LIGHT)
Draw some separator lines in the selection.
void BorderBottom(BorderStyle border=LIGHT)
Draw some separator lines to the bottom side of the selection.
void DecorateCellsAlternateRow(Decorator, int modulo=2, int shift=0)
Apply the decorator to the selection. This decorate only the corners modulo modulo with a shift of sh...
void DecorateBorderTop(Decorator)
Apply the decorator to the top border of the selection.
void DecorateSeparatorVertical(Decorator)
Apply the decorator to the vertical separators of the selection.
void BorderRight(BorderStyle border=LIGHT)
Draw some separator lines to the right side of the selection.
void Border(BorderStyle border=LIGHT)
Apply a border around the selection.
void SeparatorHorizontal(BorderStyle border=LIGHT)
Draw some horizontal separator lines in the selection.
Component Wrap(std::string name, Component component)
Definition gallery.cpp:18
Element Render()
Render the table.
Table()
Create an empty table.
TableSelection SelectCell(int column, int row)
Select a cell of the table.
TableSelection SelectColumn(int column_index)
Select a column of the table.
TableSelection SelectRow(int row_index)
Select a row of the table.
TableSelection SelectColumns(int column_min, int column_max)
Select a range of columns of the table.
TableSelection SelectRows(int row_min, int row_max)
Select a range of rows of the table.
TableSelection SelectAll()
Select all the table.
TableSelection SelectRectangle(int column_min, int column_max, int row_min, int row_max)
Select a rectangle of the table.
Decorator size(WidthOrHeight, Constraint, int value)
Apply a constraint on the size of an element.
Element flex(Element)
Make a child element to expand proportionally to the space left in a container.
Definition flex.cpp:123
Element emptyElement()
Definition dom/util.cpp:140
Element flex_shrink(Element)
Minimize if needed.
Definition flex.cpp:159
Element text(std::wstring_view text)
Display a piece of unicode text.
Definition text.cpp:164
Element automerge(Element child)
Enable character to be automatically merged with others nearby.
Definition automerge.cpp:17
Element separatorCharacter(std::string_view)
Draw a vertical or horizontal separation in between two other elements.
BorderStyle
BorderStyle is an enumeration that represents the different styles of borders that can be applied to ...
Definition elements.hpp:36
The FTXUI ftxui:: namespace.
Definition animation.hpp:10
std::function< Element(Element)> Decorator
Definition elements.hpp:25
std::shared_ptr< Node > Element
Definition elements.hpp:23
Element gridbox(std::vector< Elements > lines)
A container displaying a grid of elements.