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// このソースコードの使用は、LICENSE ファイルにある MIT ライセンスによって管理されています。
3#include "ftxui/dom/table.hpp"
4
5#include <algorithm> // for max
6#include <initializer_list> // for initializer_list
7#include <memory> // for allocator, shared_ptr, allocator_traits<>::value_type
8#include <utility> // for move, swap
9#include <vector> // for vector
10
11#include "ftxui/dom/elements.hpp" // for Element, operator|, text, separatorCharacter, Elements, BorderStyle, Decorator, emptyElement, size, gridbox, EQUAL, flex, flex_shrink, HEIGHT, WIDTH
12
13namespace ftxui {
14namespace {
15
16bool IsCell(int x, int y) {
17 return x % 2 == 1 && y % 2 == 1;
18}
19
20// NOLINTNEXTLINE
21static std::string charset[6][6] = {
22 {"┌", "┐", "└", "┘", "─", "│"}, // LIGHT
23 {"┏", "┓", "┗", "┛", "╍", "╏"}, // DASHED
24 {"┏", "┓", "┗", "┛", "━", "┃"}, // HEAVY
25 {"╔", "╗", "╚", "╝", "═", "║"}, // DOUBLE
26 {"╭", "╮", "╰", "╯", "─", "│"}, // ROUNDED
27 {" ", " ", " ", " ", " ", " "}, // EMPTY
28};
29
30int Wrap(int input, int modulo) {
31 input %= modulo;
32 input += modulo;
33 input %= modulo;
34 return input;
35}
36
37void Order(int& a, int& b) {
38 if (a >= b) {
39 std::swap(a, b);
40 }
41}
42
43} // namespace
44
45/// @brief 空のテーブルを作成します。
47 Initialize({});
48}
49
50/// @brief 文字列のベクターのベクターからテーブルを作成します。
51/// @param input 入力データ。
52Table::Table(std::vector<std::vector<std::string>> input) {
53 std::vector<std::vector<Element>> output;
54 output.reserve(input.size());
55 for (auto& row : input) {
56 output.emplace_back();
57 auto& output_row = output.back();
58 output_row.reserve(row.size());
59 for (auto& cell : row) {
60 output_row.push_back(text(std::move(cell)));
61 }
62 }
63 Initialize(std::move(output));
64}
65
66/// @brief Element のベクターのベクターからテーブルを作成します。
67/// @param input 入力要素。
68Table::Table(std::vector<std::vector<Element>> input) {
69 Initialize(std::move(input));
70}
71
72// @brief 文字列のリストのリストからテーブルを作成します。
73// @param init 入力データ。
74Table::Table(std::initializer_list<std::vector<std::string>> init) {
75 std::vector<std::vector<Element>> input;
76 for (const auto& row : init) {
77 std::vector<Element> output_row;
78 output_row.reserve(row.size());
79 for (const auto& cell : row) {
80 output_row.push_back(text(cell));
81 }
82 input.push_back(std::move(output_row));
83 }
84 Initialize(std::move(input));
85}
86
87// private
88void Table::Initialize(std::vector<std::vector<Element>> input) {
89 input_dim_y_ = static_cast<int>(input.size());
90 input_dim_x_ = 0;
91 for (auto& row : input) {
92 input_dim_x_ = std::max(input_dim_x_, int(row.size()));
93 }
94
95 dim_y_ = 2 * input_dim_y_ + 1;
96 dim_x_ = 2 * input_dim_x_ + 1;
97
98 // Reserve space.
99 elements_.resize(dim_y_);
100 for (int y = 0; y < dim_y_; ++y) {
101 elements_[y].resize(dim_x_);
102 }
103
104 // Transfert elements_ from |input| toward |elements_|.
105 {
106 int y = 1;
107 for (auto& row : input) {
108 int x = 1;
109 for (auto& cell : row) {
110 elements_[y][x] = std::move(cell);
111 x += 2;
112 }
113 y += 2;
114 }
115 }
116
117 // 境界線のために空の要素を追加します。
118 for (int y = 0; y < dim_y_; ++y) {
119 for (int x = 0; x < dim_x_; ++x) {
120 auto& element = elements_[y][x];
121
122 if (IsCell(x, y)) {
123 if (!element) {
124 element = emptyElement();
125 }
126 continue;
127 }
128
129 element = emptyElement();
130 }
131 }
132}
133
134/// @brief テーブルの行を選択します。
135/// @param index 選択する行のインデックス。
136/// @note 負のインデックスを使用して末尾から選択できます。
138 return SelectRectangle(0, -1, index, index);
139}
140
141/// @brief テーブルの行の範囲を選択します。
142/// @param row_min 選択する最初の行。
143/// @param row_max 選択する最後の行。
144/// @note 負のインデックスを使用して末尾から選択できます。
145TableSelection Table::SelectRows(int row_min, int row_max) {
146 return SelectRectangle(0, -1, row_min, row_max);
147}
148
149/// @brief テーブルの列を選択します。
150/// @param index 選択する列のインデックス。
151/// @note 負のインデックスを使用して末尾から選択できます。
153 return SelectRectangle(index, index, 0, -1);
154}
155
156/// @brief テーブルの列の範囲を選択します。
157/// @param column_min 選択する最初の列。
158/// @param column_max 選択する最後の列。
159/// @note 負のインデックスを使用して末尾から選択できます。
160TableSelection Table::SelectColumns(int column_min, int column_max) {
161 return SelectRectangle(column_min, column_max, 0, -1);
162}
163
164/// @brief テーブルのセルを選択します。
165/// @param column 選択するセルの列。
166/// @param row 選択するセルの行。
167/// @note 負のインデックスを使用して末尾から選択できます。
168TableSelection Table::SelectCell(int column, int row) {
169 return SelectRectangle(column, column, row, row);
170}
171
172/// @brief テーブルの矩形を選択します。
173/// @param column_min 選択する最初の列。
174/// @param column_max 選択する最後の列。
175/// @param row_min 選択する最初の行。
176/// @param row_max 選択する最後の行。
177/// @note 負のインデックスを使用して末尾から選択できます。
179 int column_max,
180 int row_min,
181 int row_max) {
182 column_min = Wrap(column_min, input_dim_x_);
183 column_max = Wrap(column_max, input_dim_x_);
184 Order(column_min, column_max);
185 row_min = Wrap(row_min, input_dim_y_);
186 row_max = Wrap(row_max, input_dim_y_);
187 Order(row_min, row_max);
188
189 TableSelection output; // NOLINT
190 output.table_ = this;
191 output.x_min_ = 2 * column_min;
192 output.x_max_ = 2 * column_max + 2;
193 output.y_min_ = 2 * row_min;
194 output.y_max_ = 2 * row_max + 2;
195 return output;
196}
197
198/// @brief テーブル全体を選択します。
200 TableSelection output; // NOLINT
201 output.table_ = this;
202 output.x_min_ = 0;
203 output.x_max_ = dim_x_ - 1;
204 output.y_min_ = 0;
205 output.y_max_ = dim_y_ - 1;
206 return output;
207}
208
209/// @brief テーブルをレンダリングします。
210/// @return レンダリングされたテーブル。これは描画できる要素です。
212 for (int y = 0; y < dim_y_; ++y) {
213 for (int x = 0; x < dim_x_; ++x) {
214 auto& it = elements_[y][x];
215
216 // Line
217 if ((x + y) % 2 == 1) {
218 it = std::move(it) | flex;
219 continue;
220 }
221
222 // Cells
223 if ((x % 2) == 1 && (y % 2) == 1) {
224 it = std::move(it) | flex_shrink;
225 continue;
226 }
227
228 // Corners
229 it = std::move(it) | size(WIDTH, EQUAL, 0) | size(HEIGHT, EQUAL, 0);
230 }
231 }
232 dim_x_ = 0;
233 dim_y_ = 0;
234 return gridbox(std::move(elements_));
235}
236
237/// @brief 選択範囲に `decorator` を適用します。
238/// これはセル、線、角の両方を装飾します。
239/// @param decorator 適用するデコレーター。
240// NOLINTNEXTLINE
242 for (int y = y_min_; y <= y_max_; ++y) {
243 for (int x = x_min_; x <= x_max_; ++x) {
244 Element& e = table_->elements_[y][x];
245 e = std::move(e) | decorator;
246 }
247 }
248}
249
250/// @brief 選択範囲に `decorator` を適用します。
251/// @param decorator 適用するデコレーター。
252/// これはセルのみを装飾します。
253// NOLINTNEXTLINE
255 for (int y = y_min_; y <= y_max_; ++y) {
256 for (int x = x_min_; x <= x_max_; ++x) {
257 if (y % 2 == 1 && x % 2 == 1) {
258 Element& e = table_->elements_[y][x];
259 e = std::move(e) | decorator;
260 }
261 }
262 }
263}
264
265/// @brief 選択範囲に `decorator` を適用します。
266/// これは、`modulo` でモジュロ化され、`shift` でシフトされた線のみを装飾します。
267/// @param decorator 適用するデコレーター。
268/// @param modulo 装飾する線のモジュロ。
269/// @param shift 装飾する線のシフト。
270// NOLINTNEXTLINE
272 int modulo,
273 int shift) {
274 for (int y = y_min_; y <= y_max_; ++y) {
275 for (int x = x_min_; x <= x_max_; ++x) {
276 if (y % 2 == 1 && (x / 2) % modulo == shift) {
277 Element& e = table_->elements_[y][x];
278 e = std::move(e) | decorator;
279 }
280 }
281 }
282}
283
284/// @brief 選択範囲に `decorator` を適用します。
285/// これは、`modulo` でモジュロ化され、`shift` でシフトされた線のみを装飾します。
286/// @param decorator 適用するデコレーター。
287/// @param modulo 装飾する線のモジュロ。
288/// @param shift 装飾する線のシフト。
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 選択範囲に `decorator` を適用します。
304/// これは、`modulo` でモジュロ化され、`shift` でシフトされた角のみを装飾します。
305/// @param decorator 適用するデコレーター。
306/// @param modulo 装飾する角のモジュロ。
307/// @param shift 装飾する角のシフト。
308// NOLINTNEXTLINE
310 int modulo,
311 int shift) {
312 for (int y = y_min_; y <= y_max_; ++y) {
313 for (int x = x_min_; x <= x_max_; ++x) {
314 if (y % 2 == 1 && x % 2 == 1 && ((x / 2) % modulo == shift)) {
315 Element& e = table_->elements_[y][x];
316 e = std::move(e) | decorator;
317 }
318 }
319 }
320}
321
322/// @brief 選択範囲に `decorator` を適用します。
323/// これは、`modulo` でモジュロ化され、`shift` でシフトされた角のみを装飾します。
324/// @param decorator 適用するデコレーター。
325/// @param modulo 装飾する角のモジュロ。
326/// @param shift 装飾する角のシフト。
327// NOLINTNEXTLINE
329 int modulo,
330 int shift) {
331 for (int y = y_min_; y <= y_max_; ++y) {
332 for (int x = x_min_; x <= x_max_; ++x) {
333 if (y % 2 == 1 && x % 2 == 1 && ((y / 2) % modulo == shift)) {
334 Element& e = table_->elements_[y][x];
335 e = std::move(e) | decorator;
336 }
337 }
338 }
339}
340
341/// @brief 選択範囲に `border` を適用します。
342/// @param border 適用する罫線スタイル。
344 BorderLeft(border);
345 BorderRight(border);
346 BorderTop(border);
347 BorderBottom(border);
348
349 // NOLINTNEXTLINE
350 table_->elements_[y_min_][x_min_] = text(charset[border][0]) | automerge;
351 // NOLINTNEXTLINE
352 table_->elements_[y_min_][x_max_] = text(charset[border][1]) | automerge;
353 // NOLINTNEXTLINE
354 table_->elements_[y_max_][x_min_] = text(charset[border][2]) | automerge;
355 // NOLINTNEXTLINE
356 table_->elements_[y_max_][x_max_] = text(charset[border][3]) | automerge;
357}
358
359/// @brief 選択範囲に区切り線を描画します。
360/// @param border 適用する罫線スタイル。
362 for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
363 for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
364 if (y % 2 == 0 || x % 2 == 0) {
365 Element& e = table_->elements_[y][x];
366 e = (y % 2 == 1)
367 ? separatorCharacter(charset[border][5]) | automerge // NOLINT
368 : separatorCharacter(charset[border][4]) | automerge; // NOLINT
369 }
370 }
371 }
372}
373
374/// @brief 選択範囲に垂直の区切り線を描画します。
375/// @param border 適用する罫線スタイル。
377 for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
378 for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
379 if (x % 2 == 0) {
380 table_->elements_[y][x] =
381 separatorCharacter(charset[border][5]) | automerge; // NOLINT
382 }
383 }
384 }
385}
386
387/// @brief 選択範囲に水平の区切り線を描画します。
388/// @param border 適用する罫線スタイル。
390 for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
391 for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
392 if (y % 2 == 0) {
393 table_->elements_[y][x] =
394 separatorCharacter(charset[border][4]) | automerge; // NOLINT
395 }
396 }
397 }
398}
399
400/// @brief 選択範囲の左側に区切り線を描画します。
401/// @param border 適用する罫線スタイル。
403 for (int y = y_min_; y <= y_max_; y++) {
404 table_->elements_[y][x_min_] =
405 separatorCharacter(charset[border][5]) | automerge; // NOLINT
406 }
407}
408
409/// @brief 選択範囲の右側に区切り線を描画します。
410/// @param border 適用する罫線スタイル。
412 for (int y = y_min_; y <= y_max_; y++) {
413 table_->elements_[y][x_max_] =
414 separatorCharacter(charset[border][5]) | automerge; // NOLINT
415 }
416}
417
418/// @brief 選択範囲の上側に区切り線を描画します。
419/// @param border 適用する罫線スタイル。
421 for (int x = x_min_; x <= x_max_; x++) {
422 table_->elements_[y_min_][x] =
423 separatorCharacter(charset[border][4]) | automerge; // NOLINT
424 }
425}
426
427/// @brief 選択範囲の下側に区切り線を描画します。
428/// @param border 適用する罫線スタイル。
430 for (int x = x_min_; x <= x_max_; x++) {
431 table_->elements_[y_max_][x] =
432 separatorCharacter(charset[border][4]) | automerge; // NOLINT
433 }
434}
435
436} // 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)
Definition gallery.cpp:17
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)
テーブルの矩形を選択します。
Element flex(Element)
子要素をコンテナに残されたスペースに比例して拡大させます。
Definition flex.cpp:120
Element emptyElement()
Definition dom/util.cpp:140
Element flex_shrink(Element)
必要であれば最小化します。
Definition flex.cpp:156
Element text(std::wstring text)
ユニコードテキストを表示します。
Definition text.cpp:160
Element automerge(Element child)
文字が近くの他の文字と自動的にマージされるようにします。
Definition automerge.cpp:16
BorderStyle
BorderStyleは、ターミナルUIの要素に適用できる様々なボーダースタイルを表す列挙型です。
Definition elements.hpp:31
FTXUI ftxui:: 名前空間
Definition animation.hpp:9
std::function< Element(Element)> Decorator
Definition elements.hpp:23
std::shared_ptr< Node > Element
Definition elements.hpp:21
Element separatorCharacter(std::string)
Element gridbox(std::vector< Elements > lines)
要素のグリッドを表示するコンテナ。
return size
Definition string.cpp:1516