FTXUI 6.1.9
C++ functional terminal UI.
载入中...
搜索中...
未找到
src/ftxui/dom/border.cpp
浏览该文件的文档.
1// 版权所有 2020 Arthur Sonzogni。保留所有权利。
2// 此源代码的使用受 MIT 许可证的约束,该许可证可在 LICENSE 文件中找到。
3#include <algorithm> // for max
4#include <array> // for array
5#include <ftxui/screen/color.hpp> // for Color
6#include <memory> // for allocator, make_shared, __shared_ptr_access
7#include <optional> // for optional, nullopt
8#include <string> // for basic_string, string
9#include <utility> // for move
10
11#include "ftxui/dom/elements.hpp" // for unpack, Element, Decorator, BorderStyle, ROUNDED, borderStyled, Elements, DASHED, DOUBLE, EMPTY, HEAVY, LIGHT, border, borderDashed, borderDouble, borderEmpty, borderHeavy, borderLight, borderRounded, borderWith, window
12#include "ftxui/dom/node.hpp" // for Node, Elements
13#include "ftxui/dom/requirement.hpp" // for Requirement
14#include "ftxui/screen/box.hpp" // for Box
15#include "ftxui/screen/pixel.hpp" // for Pixel
16#include "ftxui/screen/screen.hpp" // for Pixel, Screen
17
18namespace ftxui {
19
20namespace {
21using Charset = std::array<std::string, 6>; // NOLINT
22using Charsets = std::array<Charset, 6>; // NOLINT
23// NOLINTNEXTLINE
24static Charsets simple_border_charset = {
25 Charset{"┌", "┐", "└", "┘", "─", "│"}, // LIGHT
26 Charset{"┏", "┓", "┗", "┛", "╍", "╏"}, // DASHED
27 Charset{"┏", "┓", "┗", "┛", "━", "┃"}, // HEAVY
28 Charset{"╔", "╗", "╚", "╝", "═", "║"}, // DOUBLE
29 Charset{"╭", "╮", "╰", "╯", "─", "│"}, // ROUNDED
30 Charset{" ", " ", " ", " ", " ", " "}, // EMPTY
31};
32
33// 作为参考,这里是普通边框的字符集:
34 public:
35 Border(Elements children,
36 BorderStyle style,
37 std::optional<Color> foreground_color = std::nullopt)
38 : Node(std::move(children)),
39 charset_(simple_border_charset[style]) // NOLINT
40 ,
41 foreground_color_(foreground_color) {} // NOLINT
42
43 const Charset& charset_; // NOLINT
44 std::optional<Color> foreground_color_;
45
46 void ComputeRequirement() override {
48 requirement_ = children_[0]->requirement();
49 requirement_.min_x += 2;
50 requirement_.min_y += 2;
51 if (children_.size() == 2) {
52 requirement_.min_x =
53 std::max(requirement_.min_x, children_[1]->requirement().min_x + 2);
54 }
55 requirement_.focused.box.x_min++;
56 requirement_.focused.box.x_max++;
57 requirement_.focused.box.y_min++;
58 requirement_.focused.box.y_max++;
59 }
60
61 void SetBox(Box box) override {
62 Node::SetBox(box);
63 if (children_.size() == 2) {
64 Box title_box;
65 title_box.x_min = box.x_min + 1;
66 title_box.x_max = std::min(box.x_max - 1,
67 box.x_min + children_[1]->requirement().min_x);
68 title_box.y_min = box.y_min;
69 title_box.y_max = box.y_min;
70 children_[1]->SetBox(title_box);
71 }
72 box.x_min++;
73 box.x_max--;
74 box.y_min++;
75 box.y_max--;
76 children_[0]->SetBox(box);
77 }
78
79 void Render(Screen& screen) override {
80 // 绘制内容。
81 children_[0]->Render(screen);
82
83 // 绘制边框。
84 if (box_.x_min >= box_.x_max || box_.y_min >= box_.y_max) {
85 return;
86 }
87
88 screen.at(box_.x_min, box_.y_min) = charset_[0]; // NOLINT
89 screen.at(box_.x_max, box_.y_min) = charset_[1]; // NOLINT
90 screen.at(box_.x_min, box_.y_max) = charset_[2]; // NOLINT
91 screen.at(box_.x_max, box_.y_max) = charset_[3]; // NOLINT
92
93 for (int x = box_.x_min + 1; x < box_.x_max; ++x) {
94 Pixel& p1 = screen.PixelAt(x, box_.y_min);
95 Pixel& p2 = screen.PixelAt(x, box_.y_max);
96 p1.character = charset_[4]; // NOLINT
97 p2.character = charset_[4]; // NOLINT
98 p1.automerge = true;
99 p2.automerge = true;
100 }
101 for (int y = box_.y_min + 1; y < box_.y_max; ++y) {
102 Pixel& p3 = screen.PixelAt(box_.x_min, y);
103 Pixel& p4 = screen.PixelAt(box_.x_max, y);
104 p3.character = charset_[5]; // NOLINT
105 p4.character = charset_[5]; // NOLINT
106 p3.automerge = true;
107 p4.automerge = true;
108 }
109
110 // 绘制标题。
111 if (children_.size() == 2) {
112 children_[1]->Render(screen);
113 }
114
115 // 绘制边框颜色。
116 if (foreground_color_) {
117 for (int x = box_.x_min; x <= box_.x_max; ++x) {
118 screen.PixelAt(x, box_.y_min).foreground_color = *foreground_color_;
119 screen.PixelAt(x, box_.y_max).foreground_color = *foreground_color_;
120 }
121 for (int y = box_.y_min; y <= box_.y_max; ++y) {
122 screen.PixelAt(box_.x_min, y).foreground_color = *foreground_color_;
123 screen.PixelAt(box_.x_max, y).foreground_color = *foreground_color_;
124 }
125 }
126 }
127};
128
129// 作为参考,这里是普通边框的字符集:
130class BorderPixel : public Node {
131 public:
132 BorderPixel(Elements children, Pixel pixel)
133 : Node(std::move(children)), pixel_(std::move(pixel)) {}
134
135 private:
136 Pixel pixel_;
137
138 void ComputeRequirement() override {
140 requirement_ = children_[0]->requirement();
141 requirement_.min_x += 2;
142 requirement_.min_y += 2;
143 if (children_.size() == 2) {
145 std::max(requirement_.min_x, children_[1]->requirement().min_x + 2);
146 }
147
149 }
150
151 void SetBox(Box box) override {
152 Node::SetBox(box);
153 if (children_.size() == 2) {
154 Box title_box;
155 title_box.x_min = box.x_min + 1;
156 title_box.x_max = box.x_max - 1;
157 title_box.y_min = box.y_min;
158 title_box.y_max = box.y_min;
159 children_[1]->SetBox(title_box);
160 }
161 box.x_min++;
162 box.x_max--;
163 box.y_min++;
164 box.y_max--;
165 children_[0]->SetBox(box);
166 }
167
168 void Render(Screen& screen) override {
169 // Draw content.
170 children_[0]->Render(screen);
171
172 // Draw the border.
173 if (box_.x_min >= box_.x_max || box_.y_min >= box_.y_max) {
174 return;
175 }
176
177 screen.PixelAt(box_.x_min, box_.y_min) = pixel_;
178 screen.PixelAt(box_.x_max, box_.y_min) = pixel_;
179 screen.PixelAt(box_.x_min, box_.y_max) = pixel_;
180 screen.PixelAt(box_.x_max, box_.y_max) = pixel_;
181
182 for (int x = box_.x_min + 1; x < box_.x_max; ++x) {
183 screen.PixelAt(x, box_.y_min) = pixel_;
184 screen.PixelAt(x, box_.y_max) = pixel_;
185 }
186 for (int y = box_.y_min + 1; y < box_.y_max; ++y) {
187 screen.PixelAt(box_.x_min, y) = pixel_;
188 screen.PixelAt(box_.x_max, y) = pixel_;
189 }
190 }
191};
192} // namespace
193
194/// @brief 在元素周围绘制边框。
195/// @ingroup dom
196/// @see border
197/// @see borderLight
198/// @see borderDashed
199/// @see borderDouble
200/// @see borderHeavy
201/// @see borderEmpty
202/// @see borderRounded
203/// @see borderStyled
204/// @see borderWith
205///
206/// 在元素周围添加边框
207///
208/// ### 示例
209///
210/// ```cpp
211/// // 将 'border' 作为函数使用...
212/// Element document = border(text("The element"));
213///
214/// // ...或作为 '管道' 使用。
215/// Element document = text("The element") | border;
216/// ```
217///
218/// ### 输出
219///
220/// ```bash
221/// ┌───────────┐
222/// │The element│
223/// └───────────┘
224/// ```
225Element border(Element child) {
226 return std::make_shared<Border>(unpack(std::move(child)), ROUNDED);
227}
228
229/// @brief 与 border 相同,但在元素周围使用一个常量像素。
230/// @ingroup dom
231/// @see border
232Decorator borderWith(const Pixel& pixel) {
233 return [pixel](Element child) {
234 return std::make_shared<BorderPixel>(unpack(std::move(child)), pixel);
235 };
236}
237
238/// @brief 与 border 相同,但具有不同的样式。
239/// @ingroup dom
240/// @see border
241Decorator borderStyled(BorderStyle style) {
242 return [style](Element child) {
243 return std::make_shared<Border>(unpack(std::move(child)), style);
244 };
245}
246
247/// @brief 与 border 相同,但具有前景色。
248/// @ingroup dom
249/// @see border
250Decorator borderStyled(Color foreground_color) {
251 return [foreground_color](Element child) {
252 return std::make_shared<Border>(unpack(std::move(child)), ROUNDED,
253 foreground_color);
254 };
255}
256
257/// @brief 与 border 相同,但具有前景色和不同的样式。
258/// @ingroup dom
259/// @see border
260/// @ingroup dom
261/// @see border
262Decorator borderStyled(BorderStyle style, Color foreground_color) {
263 return [style, foreground_color](Element child) {
264 return std::make_shared<Border>(unpack(std::move(child)), style,
265 foreground_color);
266 };
267}
268
269/// @brief 在元素周围绘制虚线边框。
270/// @ingroup dom
271/// @see border
272/// @see borderLight
273/// @see borderDashed
274/// @see borderDouble
275/// @see borderHeavy
276/// @see borderRounded
277/// @see borderEmpty
278/// @see borderStyled
279/// @see borderWith
280///
281/// 在元素周围添加边框
282///
283/// ### 示例
284///
285/// ```cpp
286/// // 将 'borderDash' 作为函数使用...
287/// Element document = borderDash(text("The element"));
288///
289/// // ...或作为 '管道' 使用。
290/// Element document = text("The element") | borderDAsh;
291/// ```
292///
293/// ### 输出
294///
295/// ```bash
296/// ┏╍╍╍╍╍╍╍╍╍╍╍╍╍╍┓
297/// ╏The element ╏
298/// ┗╍╍╍╍╍╍╍╍╍╍╍╍╍╍┛
299/// ```
300Element borderDashed(Element child) {
301 return std::make_shared<Border>(unpack(std::move(child)), DASHED);
302}
303
304/// @brief 在元素周围绘制细边框。
305/// @ingroup dom
306/// @see border
307/// @see borderLight
308/// @see borderDashed
309/// @see borderDouble
310/// @see borderHeavy
311/// @see borderRounded
312/// @see borderEmpty
313/// @see borderStyled
314/// @see borderWith
315///
316/// 在元素周围添加边框
317///
318/// ### 示例
319///
320/// ```cpp
321/// // 将 'borderLight' 作为函数使用...
322/// Element document = borderLight(text("The element"));
323///
324/// // ...或作为 '管道' 使用。
325/// Element document = text("The element") | borderLight;
326/// ```
327///
328/// ### 输出
329///
330/// ```bash
331/// ┌──────────────┐
332/// │The element │
333/// └──────────────┘
334/// ```
335Element borderLight(Element child) {
336 return std::make_shared<Border>(unpack(std::move(child)), LIGHT);
337}
338
339/// @brief 在元素周围绘制粗边框。
340/// @ingroup dom
341/// @see border
342/// @see borderLight
343/// @see borderDashed
344/// @see borderDouble
345/// @see borderHeavy
346/// @see borderRounded
347/// @see borderEmpty
348/// @see borderStyled
349/// @see borderWith
350///
351/// 在元素周围添加边框
352///
353/// ### 示例
354///
355/// ```cpp
356/// // 将 'borderHeavy' 作为函数使用...
357/// Element document = borderHeavy(text("The element"));
358///
359/// // ...或作为 '管道' 使用。
360/// Element document = text("The element") | borderHeavy;
361/// ```
362///
363/// ### 输出
364///
365/// ```bash
366/// ┏━━━━━━━━━━━━━━┓
367/// ┃The element ┃
368/// ┗━━━━━━━━━━━━━━┛
369/// ```
370Element borderHeavy(Element child) {
371 return std::make_shared<Border>(unpack(std::move(child)), HEAVY);
372}
373
374/// @brief 在元素周围绘制双线边框。
375/// @ingroup dom
376/// @see border
377/// @see borderLight
378/// @see borderDashed
379/// @see borderDouble
380/// @see borderHeavy
381/// @see borderRounded
382/// @see borderEmpty
383/// @see borderStyled
384/// @see borderWith
385///
386/// 在元素周围添加边框
387///
388/// ### 示例
389///
390/// ```cpp
391/// // 将 'borderDouble' 作为函数使用...
392/// Element document = borderDouble(text("The element"));
393///
394/// // ...或作为 '管道' 使用。
395/// Element document = text("The element") | borderDouble;
396/// ```
397///
398/// ### 输出
399///
400/// ```bash
401/// ╔══════════════╗
402/// ║The element ║
403/// ╚══════════════╝
404/// ```
405Element borderDouble(Element child) {
406 return std::make_shared<Border>(unpack(std::move(child)), DOUBLE);
407}
408
409/// @brief 在元素周围绘制圆角边框。
410/// @ingroup dom
411/// @see border
412/// @see borderLight
413/// @see borderDashed
414/// @see borderDouble
415/// @see borderHeavy
416/// @see borderRounded
417/// @see borderEmpty
418/// @see borderStyled
419/// @see borderWith
420///
421/// 在元素周围添加边框
422///
423/// ### 示例
424///
425/// ```cpp
426/// // 将 'borderRounded' 作为函数使用...
427/// Element document = borderRounded(text("The element"));
428///
429/// // ...或作为 '管道' 使用。
430/// Element document = text("The element") | borderRounded;
431/// ```
432///
433/// ### 输出
434///
435/// ```bash
436/// ╭──────────────╮
437/// │The element │
438/// ╰──────────────╯
439/// ```
440Element borderRounded(Element child) {
441 return std::make_shared<Border>(unpack(std::move(child)), ROUNDED);
442}
443
444/// @brief 在元素周围绘制一个空边框。
445/// @ingroup dom
446/// @see border
447/// @see borderLight
448/// @see borderDashed
449/// @see borderDouble
450/// @see borderHeavy
451/// @see borderRounded
452/// @see borderEmpty
453/// @see borderStyled
454/// @see borderWith
455///
456/// 在元素周围添加边框
457///
458/// ### 示例
459///
460/// ```cpp
461/// // 将 'borderRounded' 作为函数使用...
462/// Element document = borderRounded(text("The element"));
463///
464/// // ...或作为 '管道' 使用。
465/// Element document = text("The element") | borderRounded;
466/// ```
467///
468/// ### 输出
469///
470/// ```bash
471///
472/// The element
473///
474/// ```
475Element borderEmpty(Element child) {
476 return std::make_shared<Border>(unpack(std::move(child)), EMPTY);
477}
478
479/// @brief 绘制带有标题和边框的窗口。
480/// @param title 窗口的标题。
481/// @param content 要包装的元素。
482/// @param border 边框的样式。默认为 ROUNDED。
483/// @ingroup dom
484/// @see border
485///
486/// ### 示例
487///
488/// ```cpp
489/// Element document = window(text("Title"),
490/// text("content")
491/// );
492///
493/// // 指定边框样式
494/// Element document = window(text("Title"),
495/// text("content"),
496/// ROUNDED
497/// );
498/// ```
499///
500/// ### 输出
501///
502/// ```bash
503/// ┌Title──┐
504/// │content│
505/// └───────┘
506/// ```
507Element window(Element title, Element content, BorderStyle border) {
508 return std::make_shared<Border>(unpack(std::move(content), std::move(title)),
509 border);
510}
511} // namespace ftxui
Elements children_
virtual void SetBox(Box box)
为绘图元素分配位置和尺寸。
Requirement requirement_
virtual void ComputeRequirement()
计算元素所需的空间。
friend void Render(Screen &screen, Node *node, Selection &selection)
Element window(Element title, Element content, BorderStyle border)
绘制带有标题和边框的窗口。
Element borderDouble(Element child)
在元素周围绘制双线边框。
Element borderDashed(Element child)
在元素周围绘制虚线边框。
Element borderRounded(Element child)
在元素周围绘制圆角边框。
Element borderHeavy(Element child)
在元素周围绘制粗边框。
Element borderLight(Element child)
在元素周围绘制细边框。
Decorator borderWith(const Pixel &pixel)
与 border 相同,但在元素周围使用一个常量像素。
Decorator borderStyled(BorderStyle style)
与 border 相同,但具有不同的样式。
void Render(Screen &screen, const Element &element)
在 ftxui::Screen 上显示元素。
Element border(Element child)
在元素周围绘制边框。
Element borderEmpty(Element child)
在元素周围绘制一个空边框。
BorderStyle
BorderStyle 是一个枚举,表示可应用于终端 UI 中元素的不同边框样式。
void Shift(int x, int y)
定义 box.cpp:34
#include "ftxui/component/component_base.hpp" // 用于 ComponentBase
std::vector< Element > Elements