FTXUI 6.1.9
C++ functional terminal UI.
载入中...
搜索中...
未找到
src/ftxui/dom/separator.cpp
浏览该文件的文档.
1// 版权所有 2020 Arthur Sonzogni。保留所有权利。
2// 本源代码的使用受 MIT 许可证的约束,该许可证可在 LICENSE 文件中找到。
3#include <array> // for array, array<>::value_type
4#include <memory> // for make_shared, allocator
5#include <string> // for basic_string, string
6#include <utility> // for move
7
8#include "ftxui/dom/elements.hpp" // for Element, BorderStyle, LIGHT, separator, DOUBLE, EMPTY, HEAVY, separatorCharacter, separatorDouble, separatorEmpty, separatorHSelector, separatorHeavy, separatorLight, separatorStyled, separatorVSelector
9#include "ftxui/dom/node.hpp" // for Node
10#include "ftxui/dom/requirement.hpp" // for Requirement
11#include "ftxui/screen/box.hpp" // for Box
12#include "ftxui/screen/color.hpp" // for Color
13#include "ftxui/screen/pixel.hpp" // for Pixel
14#include "ftxui/screen/screen.hpp" // for Pixel, Screen
15
16namespace ftxui {
17
18namespace {
19using Charset = std::array<std::string, 2>; // NOLINT
20using Charsets = std::array<Charset, 6>; // NOLINT
21// NOLINTNEXTLINE
22const Charsets charsets = {
23 Charset{"│", "─"}, // LIGHT
24 Charset{"╏", "╍"}, // DASHED
25 Charset{"┃", "━"}, // HEAVY
26 Charset{"║", "═"}, // DOUBLE
27 Charset{"│", "─"}, // ROUNDED
28 Charset{" ", " "}, // EMPTY
29};
30
31class Separator : public Node {
32 public:
33 explicit Separator(std::string value) : value_(std::move(value)) {}
34
35 void ComputeRequirement() override {
36 requirement_.min_x = 1;
37 requirement_.min_y = 1;
38 }
39
40 void Render(Screen& screen) override {
41 for (int y = box_.y_min; y <= box_.y_max; ++y) {
42 for (int x = box_.x_min; x <= box_.x_max; ++x) {
43 Pixel& pixel = screen.PixelAt(x, y);
44 pixel.character = value_;
45 pixel.automerge = true;
46 }
47 }
48 }
49
50 std::string value_;
51};
52
53class SeparatorAuto : public Node {
54 public:
55 explicit SeparatorAuto(BorderStyle style) : style_(style) {}
56
57 void ComputeRequirement() override {
58 requirement_.min_x = 1;
59 requirement_.min_y = 1;
60 }
61
62 void Render(Screen& screen) override {
63 const bool is_column = (box_.x_max == box_.x_min);
64 const bool is_line = (box_.y_min == box_.y_max);
65
66 const std::string c =
67 charsets[style_][int(is_line && !is_column)]; // NOLINT
68
69 for (int y = box_.y_min; y <= box_.y_max; ++y) {
70 for (int x = box_.x_min; x <= box_.x_max; ++x) {
71 Pixel& pixel = screen.PixelAt(x, y);
72 pixel.character = c;
73 pixel.automerge = true;
74 }
75 }
76 }
77
79};
80
81class SeparatorWithPixel : public SeparatorAuto {
82 public:
83 explicit SeparatorWithPixel(Pixel pixel)
84 : SeparatorAuto(LIGHT), pixel_(std::move(pixel)) {
85 pixel_.automerge = true;
86 }
87 void Render(Screen& screen) override {
88 for (int y = box_.y_min; y <= box_.y_max; ++y) {
89 for (int x = box_.x_min; x <= box_.x_max; ++x) {
90 screen.PixelAt(x, y) = pixel_;
91 }
92 }
93 }
94
95 private:
96 Pixel pixel_;
97};
98} // namespace
99
100/// @brief 在两个其他元素之间绘制垂直或水平分隔线。
101/// @ingroup dom
102/// @see separator
103/// @see separatorLight
104/// @see separatorDashed
105/// @see separatorDouble
106/// @see separatorHeavy
107/// @see separatorEmpty
108/// @see separatorRounded
109/// @see separatorStyled
110/// @see separatorCharacter
111///
112/// 在两个元素之间添加视觉分隔。
113///
114/// ### 示例
115///
116/// ```cpp
117/// // 将“border”用作函数...
118/// Element document = vbox({
119/// text("up"),
120/// separator(),
121/// text("down"),
122/// });
123/// ```
124///
125/// ### 输出
126///
127/// ```bash
128/// up
129/// ────
130/// down
131/// ```
133 return std::make_shared<SeparatorAuto>(LIGHT);
134}
135
136/// @brief 在两个其他元素之间绘制垂直或水平分隔线。
137/// @param style 分隔线的样式。
138/// @ingroup dom
139/// @see separator
140/// @see separatorLight
141/// @see separatorDashed
142/// @see separatorDouble
143/// @see separatorHeavy
144/// @see separatorEmpty
145/// @see separatorRounded
146/// @see separatorStyled
147/// @see separatorCharacter
148///
149/// 在两个元素之间添加视觉分隔。
150///
151/// ### 示例
152///
153/// ```cpp
154/// // 将“border”用作函数...
155/// Element document = vbox({
156/// text("up"),
157/// separatorStyled(DOUBLE),
158/// text("down"),
159/// });
160/// ```
161///
162/// ### 输出
163///
164/// ```bash
165/// up
166/// ════
167/// down
168/// ```
170 return std::make_shared<SeparatorAuto>(style);
171}
172
173/// @brief 使用 LIGHT 样式在两个其他元素之间绘制垂直或水平分隔线。
174/// @ingroup dom
175/// @see separator
176/// @see separatorLight
177/// @see separatorDashed
178/// @see separatorDouble
179/// @see separatorHeavy
180/// @see separatorEmpty
181/// @see separatorRounded
182/// @see separatorStyled
183/// @see separatorCharacter
184///
185/// 在两个元素之间添加视觉分隔。
186///
187/// ### 示例
188///
189/// ```cpp
190/// // 将“border”用作函数...
191/// Element document = vbox({
192/// text("up"),
193/// separatorLight(),
194/// text("down"),
195/// });
196/// ```
197///
198/// ### 输出
199///
200/// ```bash
201/// up
202/// ────
203/// down
204/// ```
206 return std::make_shared<SeparatorAuto>(LIGHT);
207}
208
209/// @brief 使用 DASHED 样式在两个其他元素之间绘制垂直或水平分隔线。
210/// @ingroup dom
211/// @see separator
212/// @see separatorLight
213/// @see separatorDashed
214/// @see separatorDouble
215/// @see separatorHeavy
216/// @see separatorEmpty
217/// @see separatorRounded
218/// @see separatorStyled
219/// @see separatorCharacter
220///
221/// 在两个元素之间添加视觉分隔。
222///
223/// ### 示例
224///
225/// ```cpp
226/// // 将“border”用作函数...
227/// Element document = vbox({
228/// text("up"),
229/// separatorLight(),
230/// text("down"),
231/// });
232/// ```
233///
234/// ### 输出
235///
236/// ```bash
237/// up
238/// ╍╍╍╍
239/// down
240/// ```
242 return std::make_shared<SeparatorAuto>(DASHED);
243}
244
245/// @brief 使用 HEAVY 样式在两个其他元素之间绘制垂直或水平分隔线。
246/// @ingroup dom
247/// @see separator
248/// @see separatorLight
249/// @see separatorDashed
250/// @see separatorDouble
251/// @see separatorHeavy
252/// @see separatorEmpty
253/// @see separatorRounded
254/// @see separatorStyled
255/// @see separatorCharacter
256///
257/// 在两个元素之间添加视觉分隔。
258///
259/// ### 示例
260///
261/// ```cpp
262/// // 将“border”用作函数...
263/// Element document = vbox({
264/// text("up"),
265/// separatorHeavy(),
266/// text("down"),
267/// });
268/// ```
269///
270/// ### 输出
271///
272/// ```bash
273/// up
274/// ━━━━
275/// down
276/// ```
278 return std::make_shared<SeparatorAuto>(HEAVY);
279}
280
281/// @brief 使用 DOUBLE 样式在两个其他元素之间绘制垂直或水平分隔线。
282/// @ingroup dom
283/// @see separator
284/// @see separatorLight
285/// @see separatorDashed
286/// @see separatorDouble
287/// @see separatorHeavy
288/// @see separatorEmpty
289/// @see separatorRounded
290/// @see separatorStyled
291/// @see separatorCharacter
292///
293/// 在两个元素之间添加视觉分隔。
294///
295/// ### 示例
296///
297/// ```cpp
298/// // 将“border”用作函数...
299/// Element document = vbox({
300/// text("up"),
301/// separatorDouble(),
302/// text("down"),
303/// });
304/// ```
305///
306/// ### 输出
307///
308/// ```bash
309/// up
310/// ════
311/// down
312/// ```
314 return std::make_shared<SeparatorAuto>(DOUBLE);
315}
316
317/// @brief 使用 EMPTY 样式在两个其他元素之间绘制垂直或水平分隔线。
318/// @ingroup dom
319/// @see separator
320/// @see separatorLight
321/// @see separatorDashed
322/// @see separatorDouble
323/// @see separatorHeavy
324/// @see separatorEmpty
325/// @see separatorRounded
326/// @see separatorStyled
327/// @see separatorCharacter
328///
329/// 在两个元素之间添加视觉分隔。
330///
331/// ### 示例
332///
333/// ```cpp
334/// // 将“border”用作函数...
335/// Element document = vbox({
336/// text("up"),
337/// separator(),
338/// text("down"),
339/// });
340/// ```
341///
342/// ### 输出
343///
344/// ```bash
345/// up
346///
347/// down
348/// ```
350 return std::make_shared<SeparatorAuto>(EMPTY);
351}
352
353/// @brief 在两个其他元素之间绘制垂直或水平分隔线。
354/// @param value 用于填充分隔区域的字符。
355/// @ingroup dom
356/// @see separator
357/// @see separatorLight
358/// @see separatorDashed
359/// @see separatorDouble
360/// @see separatorHeavy
361/// @see separatorEmpty
362/// @see separatorRounded
363/// @see separatorStyled
364/// @see separatorCharacter
365///
366/// 在两个元素之间添加视觉分隔。
367///
368/// ### 示例
369///
370/// ```cpp
371/// // 将“border”用作函数...
372/// Element document = vbox({
373/// text("up"),
374/// separator(),
375/// text("down"),
376/// });
377/// ```
378///
379/// ### 输出
380///
381/// ```bash
382/// up
383/// ────
384/// down
385/// ```
386Element separatorCharacter(std::string value) {
387 return std::make_shared<Separator>(std::move(value));
388}
389
390/// @brief 在两个元素之间绘制用给定像素填充的分隔线。
391/// @ingroup dom
392/// @see separator
393/// @see separatorLight
394/// @see separatorDashed
395/// @see separatorHeavy
396/// @see separatorDouble
397/// @see separatorStyled
398///
399/// ### 示例
400///
401/// ```cpp
402/// Pixel empty;
403/// Element document = vbox({
404/// text("Up"),
405/// separator(empty),
406/// text("Down"),
407/// })
408/// ```
409///
410/// ### 输出
411///
412/// ```bash
413/// Up
414///
415/// Down
416/// ```
418 return std::make_shared<SeparatorWithPixel>(std::move(pixel));
419}
420
421/// @brief 绘制一个水平条,左右区域颜色不同。
422/// @param left 活动区域的左侧限制。
423/// @param right 活动区域的右侧限制。
424/// @param selected_color 选定区域的颜色。
425/// @param unselected_color 未选定区域的颜色。
426///
427/// ### 示例
428///
429/// ```cpp
430/// Element document = separatorHSelector(2,5, Color::White, Color::Blue);
431/// ```
433 float right,
434 Color unselected_color,
435 Color selected_color) {
436 class Impl : public Node {
437 public:
438 Impl(float left, float right, Color selected_color, Color unselected_color)
439 : left_(left),
440 right_(right),
441 unselected_color_(unselected_color),
442 selected_color_(selected_color) {}
443 void ComputeRequirement() override {
444 requirement_.min_x = 1;
445 requirement_.min_y = 1;
446 }
447
448 void Render(Screen& screen) override {
449 if (box_.y_max < box_.y_min) {
450 return;
451 }
452
453 // This are the two location with an empty demi-cell.
454 int demi_cell_left = int(left_ * 2.F - 1.F); // NOLINT
455 int demi_cell_right = int(right_ * 2.F + 2.F); // NOLINT
456
457 const int y = box_.y_min;
458 for (int x = box_.x_min; x <= box_.x_max; ++x) {
459 Pixel& pixel = screen.PixelAt(x, y);
460
461 const int a = (x - box_.x_min) * 2;
462 const int b = a + 1;
463 const bool a_empty = demi_cell_left == a || demi_cell_right == a;
464 const bool b_empty = demi_cell_left == b || demi_cell_right == b;
465
466 if (!a_empty && !b_empty) {
467 pixel.character = "─";
468 pixel.automerge = true;
469 } else {
470 pixel.character = a_empty ? "╶" : "╴"; // NOLINT
471 pixel.automerge = false;
472 }
473
474 if (demi_cell_left <= a && b <= demi_cell_right) {
475 pixel.foreground_color = selected_color_;
476 } else {
477 pixel.foreground_color = unselected_color_;
478 }
479 }
480 }
481
482 float left_;
483 float right_;
484 Color unselected_color_;
485 Color selected_color_;
486 };
487 return std::make_shared<Impl>(left, right, unselected_color, selected_color);
488}
489
490/// @brief 绘制一个垂直条,上下区域颜色不同。
491/// @param up 活动区域的左侧限制。
492/// @param down 活动区域的右侧限制。
493/// @param selected_color 选定区域的颜色。
494/// @param unselected_color 未选定区域的颜色。
495///
496/// ### 示例
497///
498/// ```cpp
499/// Element document = separatorHSelector(2,5, Color::White, Color::Blue);
500/// ```
502 float down,
503 Color unselected_color,
504 Color selected_color) {
505 class Impl : public Node {
506 public:
507 Impl(float up, float down, Color unselected_color, Color selected_color)
508 : up_(up),
509 down_(down),
510 unselected_color_(unselected_color),
511 selected_color_(selected_color) {}
512 void ComputeRequirement() override {
513 requirement_.min_x = 1;
514 requirement_.min_y = 1;
515 }
516
517 void Render(Screen& screen) override {
518 if (box_.x_max < box_.x_min) {
519 return;
520 }
521
522 // This are the two location with an empty demi-cell.
523 const int demi_cell_up = int(up_ * 2 - 1);
524 const int demi_cell_down = int(down_ * 2 + 2);
525
526 const int x = box_.x_min;
527 for (int y = box_.y_min; y <= box_.y_max; ++y) {
528 Pixel& pixel = screen.PixelAt(x, y);
529
530 const int a = (y - box_.y_min) * 2;
531 const int b = a + 1;
532 const bool a_empty = demi_cell_up == a || demi_cell_down == a;
533 const bool b_empty = demi_cell_up == b || demi_cell_down == b;
534
535 if (!a_empty && !b_empty) {
536 pixel.character = "│";
537 pixel.automerge = true;
538 } else {
539 pixel.character = a_empty ? "╷" : "╵"; // NOLINT
540 pixel.automerge = false;
541 }
542
543 if (demi_cell_up <= a && b <= demi_cell_down) {
544 pixel.foreground_color = selected_color_;
545 } else {
546 pixel.foreground_color = unselected_color_;
547 }
548 }
549 }
550
551 float up_;
552 float down_;
553 Color unselected_color_;
554 Color selected_color_;
555 };
556 return std::make_shared<Impl>(up, down, unselected_color, selected_color);
557}
558
559} // namespace ftxui
Node 是 DOM 树中所有元素的基类。
Element separatorStyled(BorderStyle)
在两个其他元素之间绘制垂直或水平分隔线。
Element separatorEmpty()
使用 EMPTY 样式在两个其他元素之间绘制垂直或水平分隔线。
Element separatorLight()
使用 LIGHT 样式在两个其他元素之间绘制垂直或水平分隔线。
Element separatorDashed()
使用 DASHED 样式在两个其他元素之间绘制垂直或水平分隔线。
Element separatorCharacter(std::string)
在两个其他元素之间绘制垂直或水平分隔线。
Element separator()
在两个其他元素之间绘制垂直或水平分隔线。
void Render(Screen &screen, const Element &element)
在 ftxui::Screen 上显示元素。
Element separatorDouble()
使用 DOUBLE 样式在两个其他元素之间绘制垂直或水平分隔线。
Element separatorHeavy()
使用 HEAVY 样式在两个其他元素之间绘制垂直或水平分隔线。
BorderStyle
BorderStyle 是一个枚举,表示可应用于终端 UI 中元素的不同边框样式。
Color foreground_color
std::string character
Pixel & PixelAt(int x, int y)
访问给定位置的单元格 (Pixel)。
Color 是一个表示终端用户界面中颜色的类。
像素的矩形网格。
一个 Unicode 字符及其相关样式。
#include "ftxui/component/component_base.hpp" // 用于 ComponentBase
Element separatorVSelector(float up, float down, Color unselected_color, Color selected_color)
绘制一个垂直条,上下区域颜色不同。
std::shared_ptr< Node > Element
Element separatorHSelector(float left, float right, Color unselected_color, Color selected_color)
绘制一个水平条,左右区域颜色不同。
std::uint8_t left
std::uint8_t down
std::uint8_t right
std::function< void(Pixel &)> style_
std::string value_