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