FTXUI 6.1.9
C++ functional terminal UI.
载入中...
搜索中...
未找到
src/ftxui/dom/table.cpp
浏览该文件的文档.
1// Copyright 2021 Arthur Sonzogni. 保留所有权利。
2// 本源代码的使用受 MIT 许可证的约束,该许可证可在以下位置找到
3// LICENSE 文件。
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 {"┌", "┐", "└", "┘", "─", "│"}, // 亮
24 {"┏", "┓", "┗", "┛", "╍", "╏"}, // 虚线
25 {"┏", "┓", "┗", "┛", "━", "┃"}, // 粗线
26 {"╔", "╗", "╚", "╝", "═", "║"}, // 双线
27 {"╭", "╮", "╰", "╯", "─", "│"}, // 圆角
28 {" ", " ", " ", " ", " ", " "}, // 空
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 创建一个空表格。
48 Initialize({});
49}
50
51/// @brief 从字符串向量的向量创建表格。
52/// @param input 输入数据。
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 从 Element 向量的向量创建表格
68/// @param input 输入元素。
69Table::Table(std::vector<std::vector<Element>> input) {
70 Initialize(std::move(input));
71}
72
73// @brief 从字符串列表的列表创建表格。
74// @param init 输入数据。
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// 私有
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 // 预留空间。
100 elements_.resize(dim_y_);
101 for (int y = 0; y < dim_y_; ++y) {
102 elements_[y].resize(dim_x_);
103 }
104
105 // 将 elements_ 从 |input| 转移到 |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 // 为边框添加空元素。
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 选择表格的一行。
136/// @param index 要选择的行的索引。
137/// @note 您可以使用负索引从末尾选择。
139 return SelectRectangle(0, -1, index, index);
140}
141
142/// @brief 选择表格的行范围。
143/// @param row_min 要选择的第一行。
144/// @param row_max 要选择的最后一行。
145/// @note 您可以使用负索引从末尾选择。
146TableSelection Table::SelectRows(int row_min, int row_max) {
147 return SelectRectangle(0, -1, row_min, row_max);
148}
149
150/// @brief 选择表格的一列。
151/// @param index 要选择的列的索引。
152/// @note 您可以使用负索引从末尾选择。
154 return SelectRectangle(index, index, 0, -1);
155}
156
157/// @brief 选择表格的列范围。
158/// @param column_min 要选择的第一列。
159/// @param column_max 要选择的最后一列。
160/// @note 您可以使用负索引从末尾选择。
161TableSelection Table::SelectColumns(int column_min, int column_max) {
162 return SelectRectangle(column_min, column_max, 0, -1);
163}
164
165/// @brief 选择表格的一个单元格。
166/// @param column 要选择的单元格的列。
167/// @param row 要选择的单元格的行。
168/// @note 您可以使用负索引从末尾选择。
169TableSelection Table::SelectCell(int column, int row) {
170 return SelectRectangle(column, column, row, row);
171}
172
173/// @brief 选择表格的一个矩形区域。
174/// @param column_min 要选择的第一列。
175/// @param column_max 要选择的最后一列。
176/// @param row_min 要选择的第一行。
177/// @param row_max 要选择的最后一行。
178/// @note 您可以使用负索引从末尾选择。
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 选择整个表格。
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 渲染表格。
211/// @return 渲染的表格。这是一个您可以绘制的元素。
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 将 `decorator` 应用于选择。
239/// 这将装饰单元格、线条和角。
240/// @param decorator 要应用的装饰器。
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 将 `decorator` 应用于选择。
252/// @param decorator 要应用的装饰器。
253/// 这只装饰单元格。
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 将 `decorator` 应用于选择。
267/// 这只装饰模数为 `modulo` 且偏移量为 `shift` 的线条。
268/// @param decorator 要应用的装饰器。
269/// @param modulo 要装饰线条的模数。
270/// @param shift 要装饰线条的偏移量。
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 将 `decorator` 应用于选择。
286/// 这只装饰模数为 `modulo` 且偏移量为 `shift` 的线条。
287/// @param decorator 要应用的装饰器。
288/// @param modulo 要装饰线条的模数。
289/// @param shift 要装饰线条的偏移量。
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 将 `decorator` 应用于选择。
305/// 这只装饰模数为 `modulo` 且偏移量为 `shift` 的角。
306/// @param decorator 要应用的装饰器。
307/// @param modulo 要装饰角的模数。
308/// @param shift 要装饰角的偏移量。
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 将 `decorator` 应用于选择。
324/// 这只装饰模数为 `modulo` 且偏移量为 `shift` 的角。
325/// @param decorator 要应用的装饰器。
326/// @param modulo 要装饰角的模数。
327/// @param shift 要装饰角的偏移量。
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 在选择周围应用 `border`。
343/// @param border 要应用的边框样式。
345 BorderLeft(border);
346 BorderRight(border);
347 BorderTop(border);
348 BorderBottom(border);
349
350 // NOLINTNEXTLINE
351 table_->elements_[y_min_][x_min_] = text(charset[border][0]) | automerge;
352 // NOLINTNEXTLINE
353 table_->elements_[y_min_][x_max_] = text(charset[border][1]) | automerge;
354 // NOLINTNEXTLINE
355 table_->elements_[y_max_][x_min_] = text(charset[border][2]) | automerge;
356 // NOLINTNEXTLINE
357 table_->elements_[y_max_][x_max_] = text(charset[border][3]) | automerge;
358}
359
360/// @brief 在选择中绘制一些分隔线。
361/// @param border 要应用的边框样式。
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];
367 e = (y % 2 == 1)
368 ? separatorCharacter(charset[border][5]) | automerge // NOLINT
369 : separatorCharacter(charset[border][4]) | automerge; // NOLINT
370 }
371 }
372 }
373}
374
375/// @brief 在选择中绘制一些垂直分隔线。
376/// @param border 要应用的边框样式。
378 for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
379 for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
380 if (x % 2 == 0) {
381 table_->elements_[y][x] =
382 separatorCharacter(charset[border][5]) | automerge; // NOLINT
383 }
384 }
385 }
386}
387
388/// @brief 在选择中绘制一些水平分隔线。
389/// @param border 要应用的边框样式。
391 for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
392 for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
393 if (y % 2 == 0) {
394 table_->elements_[y][x] =
395 separatorCharacter(charset[border][4]) | automerge; // NOLINT
396 }
397 }
398 }
399}
400
401/// @brief 在选择的左侧绘制一些分隔线。
402/// @param border 要应用的边框样式。
404 for (int y = y_min_; y <= y_max_; y++) {
405 table_->elements_[y][x_min_] =
406 separatorCharacter(charset[border][5]) | automerge; // NOLINT
407 }
408}
409
410/// @brief 在选择的右侧绘制一些分隔线。
411/// @param border 要应用的边框样式。
413 for (int y = y_min_; y <= y_max_; y++) {
414 table_->elements_[y][x_max_] =
415 separatorCharacter(charset[border][5]) | automerge; // NOLINT
416 }
417}
418
419/// @brief 在选择的顶部绘制一些分隔线。
420/// @param border 要应用的边框样式。
422 for (int x = x_min_; x <= x_max_; x++) {
423 table_->elements_[y_min_][x] =
424 separatorCharacter(charset[border][4]) | automerge; // NOLINT
425 }
426}
427
428/// @brief 在选择的底部绘制一些分隔线。
429/// @param border 要应用的边框样式。
431 for (int x = x_min_; x <= x_max_; x++) {
432 table_->elements_[y_max_][x] =
433 separatorCharacter(charset[border][4]) | automerge; // NOLINT
434 }
435}
436
437} // namespace ftxui
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)
Element Render()
渲染表格。
Table()
创建一个空表格。
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 emptyElement()
Element flex_shrink(Element)
如果需要,进行收缩。
Element text(std::wstring text)
显示一段Unicode文本。
Element separatorCharacter(std::string)
在两个其他元素之间绘制垂直或水平分隔线。
Element automerge(Element child)
启用字符自动与附近的其它字符合并。
BorderStyle
BorderStyle 是一个枚举,表示可应用于终端 UI 中元素的不同边框样式。
#include "ftxui/component/component_base.hpp" // 用于 ComponentBase
std::function< Element(Element)> Decorator
std::shared_ptr< Node > Element
Element gridbox(std::vector< Elements > lines)
一个显示元素网格的容器。