FTXUI 6.1.9
C++ functional terminal UI.
Loading...
Searching...
No Matches
src/ftxui/dom/separator.cpp
Go to the documentation of this file.
1// Copyright 2020 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 <array> // for array, array<>::value_type
5#include <memory> // for make_shared, allocator
6#include <string> // for basic_string, string
7#include <utility> // for move
8
9#include "ftxui/dom/elements.hpp" // for Element, BorderStyle, LIGHT, separator, DOUBLE, EMPTY, HEAVY, separatorCharacter, separatorDouble, separatorEmpty, separatorHSelector, separatorHeavy, separatorLight, separatorStyled, separatorVSelector
10#include "ftxui/dom/node.hpp" // for Node
11#include "ftxui/dom/requirement.hpp" // for Requirement
12#include "ftxui/screen/box.hpp" // for Box
13#include "ftxui/screen/color.hpp" // for Color
14#include "ftxui/screen/pixel.hpp" // for Pixel
15#include "ftxui/screen/screen.hpp" // for Pixel, Screen
16
17namespace ftxui {
18
19namespace {
20using Charset = std::array<std::string, 2>; // NOLINT
21using Charsets = std::array<Charset, 6>; // NOLINT
22// NOLINTNEXTLINE
23const Charsets charsets = {
24 Charset{"│", "─"}, // LIGHT
25 Charset{"╏", "╍"}, // DASHED
26 Charset{"┃", "━"}, // HEAVY
27 Charset{"║", "═"}, // DOUBLE
28 Charset{"│", "─"}, // ROUNDED
29 Charset{" ", " "}, // EMPTY
30};
31
32class Separator : public Node {
33 public:
34 explicit Separator(std::string value) : value_(std::move(value)) {}
35
36 void ComputeRequirement() override {
37 requirement_.min_x = 1;
38 requirement_.min_y = 1;
39 }
40
41 void Render(Screen& screen) override {
42 for (int y = box_.y_min; y <= box_.y_max; ++y) {
43 for (int x = box_.x_min; x <= box_.x_max; ++x) {
44 Pixel& pixel = screen.PixelAt(x, y);
45 pixel.character = value_;
46 pixel.automerge = true;
47 }
48 }
49 }
50
51 std::string value_;
52};
53
54class SeparatorAuto : public Node {
55 public:
56 explicit SeparatorAuto(BorderStyle style) : style_(style) {}
57
58 void ComputeRequirement() override {
59 requirement_.min_x = 1;
60 requirement_.min_y = 1;
61 }
62
63 void Render(Screen& screen) override {
64 const bool is_column = (box_.x_max == box_.x_min);
65 const bool is_line = (box_.y_min == box_.y_max);
66
67 const std::string c =
68 charsets[style_][int(is_line && !is_column)]; // NOLINT
69
70 for (int y = box_.y_min; y <= box_.y_max; ++y) {
71 for (int x = box_.x_min; x <= box_.x_max; ++x) {
72 Pixel& pixel = screen.PixelAt(x, y);
73 pixel.character = c;
74 pixel.automerge = true;
75 }
76 }
77 }
78
80};
81
82class SeparatorWithPixel : public SeparatorAuto {
83 public:
84 explicit SeparatorWithPixel(Pixel pixel)
85 : SeparatorAuto(LIGHT), pixel_(std::move(pixel)) {
86 pixel_.automerge = true;
87 }
88 void Render(Screen& screen) override {
89 for (int y = box_.y_min; y <= box_.y_max; ++y) {
90 for (int x = box_.x_min; x <= box_.x_max; ++x) {
91 screen.PixelAt(x, y) = pixel_;
92 }
93 }
94 }
95
96 private:
97 Pixel pixel_;
98};
99} // namespace
100
101/// @brief 他の2つの要素の間に垂直または水平の区切り線を描画します。
102/// @ingroup dom
103/// @see separator
104/// @see separatorLight
105/// @see separatorDashed
106/// @see separatorDouble
107/// @see separatorHeavy
108/// @see separatorEmpty
109/// @see separatorRounded
110/// @see separatorStyled
111/// @see separatorCharacter
112///
113/// 2つの要素間に視覚的な区切りを追加します。
114///
115/// ### Example
116///
117/// ```cpp
118/// // 関数として \'border\' を使用...
119/// Element document = vbox({
120/// text("up"),
121/// separator(),
122/// text("down"),
123/// });
125 return std::make_shared<SeparatorAuto>(LIGHT);
126}
127
128/// @brief 他の2つの要素の間に垂直または水平の区切り線を描画します。
129/// @param style 区切り線のスタイル。
130/// @ingroup dom
131/// @see separator
132/// @see separatorLight
133/// @see separatorDashed
134/// @see separatorDouble
135/// @see separatorHeavy
136/// @see separatorEmpty
137/// @see separatorRounded
138/// @see separatorStyled
139/// @see separatorCharacter
140///
141/// 2つの要素間に視覚的な区切りを追加します。
142///
143/// ### Example
144///
145/// ```cpp
146/// // 関数として \'border\' を使用...
147/// Element document = vbox({
148/// text("up"),
149/// separatorStyled(DOUBLE),
150/// text("down"),
151/// });
153 return std::make_shared<SeparatorAuto>(style);
154}
155
156/// @brief 他の2つの要素の間にLIGHTスタイルで垂直または水平の区切り線を描画します。
157/// @ingroup dom
158/// @see separator
159/// @see separatorLight
160/// @see separatorDashed
161/// @see separatorDouble
162/// @see separatorHeavy
163/// @see separatorEmpty
164/// @see separatorRounded
165/// @see separatorStyled
166/// @see separatorCharacter
167///
168/// 2つの要素間に視覚的な区切りを追加します。
169///
170/// ### Example
171///
172/// ```cpp
173/// // 関数として \'border\' を使用...
174/// Element document = vbox({
175/// text("up"),
176/// separatorLight(),
177/// text("down"),
178/// });
180 return std::make_shared<SeparatorAuto>(LIGHT);
181}
182
183/// @brief 他の2つの要素の間にDASHEDスタイルで垂直または水平の区切り線を描画します。
184/// @ingroup dom
185/// @see separator
186/// @see separatorLight
187/// @see separatorDashed
188/// @see separatorDouble
189/// @see separatorHeavy
190/// @see separatorEmpty
191/// @see separatorRounded
192/// @see separatorStyled
193/// @see separatorCharacter
194///
195/// 2つの要素間に視覚的な区切りを追加します。
196///
197/// ### Example
198///
199/// ```cpp
200/// // 関数として \'border\' を使用...
201/// Element document = vbox({
202/// text("up"),
203/// separatorDashed(),
204/// text("down"),
205/// });
207 return std::make_shared<SeparatorAuto>(DASHED);
208}
209
210/// @brief 他の2つの要素の間にHEAVYスタイルで垂直または水平の区切り線を描画します。
211/// @ingroup dom
212/// @see separator
213/// @see separatorLight
214/// @see separatorDashed
215/// @see separatorDouble
216/// @see separatorHeavy
217/// @see separatorEmpty
218/// @see separatorRounded
219/// @see separatorStyled
220/// @see separatorCharacter
221///
222/// 2つの要素間に視覚的な区切りを追加します。
223///
224/// ### Example
225///
226/// ```cpp
227/// // 関数として \'border\' を使用...
228/// Element document = vbox({
229/// text("up"),
230/// separatorHeavy(),
231/// text("down"),
232/// });
234 return std::make_shared<SeparatorAuto>(HEAVY);
235}
236
237/// @brief 他の2つの要素の間にDOUBLEスタイルで垂直または水平の区切り線を描画します。
238/// @ingroup dom
239/// @see separator
240/// @see separatorLight
241/// @see separatorDashed
242/// @see separatorDouble
243/// @see separatorHeavy
244/// @see separatorEmpty
245/// @see separatorRounded
246/// @see separatorStyled
247/// @see separatorCharacter
248///
249/// 2つの要素間に視覚的な区切りを追加します。
250///
251/// ### Example
252///
253/// ```cpp
254/// // 関数として \'border\' を使用...
255/// Element document = vbox({
256/// text("up"),
257/// separatorDouble(),
258/// text("down"),
259/// });
261 return std::make_shared<SeparatorAuto>(DOUBLE);
262}
263
264/// @brief 他の2つの要素の間にEMPTYスタイルで垂直または水平の区切り線を描画します。
265/// @ingroup dom
266/// @see separator
267/// @see separatorLight
268/// @see separatorDashed
269/// @see separatorDouble
270/// @see separatorHeavy
271/// @see separatorEmpty
272/// @see separatorRounded
273/// @see separatorStyled
274/// @see separatorCharacter
275///
276/// 2つの要素間に視覚的な区切りを追加します。
277///
278/// ### Example
279///
280/// ```cpp
281/// // 関数として \'border\' を使用...
282/// Element document = vbox({
283/// text("up"),
284/// separatorEmpty(),
285/// text("down"),
286/// });
287/// ```
288///
289/// ### Output
290///
291/// ```bash
292/// up
293///
294/// down
295/// ```
297 return std::make_shared<SeparatorAuto>(EMPTY);
298}
299
300/// @brief 他の2つの要素の間に垂直または水平の区切り線を描画します。
301/// @param value 区切り領域を埋める文字。
302/// @ingroup dom
303/// @see separator
304/// @see separatorLight
305/// @see separatorDashed
306/// @see separatorDouble
307/// @see separatorHeavy
308/// @see separatorEmpty
309/// @see separatorRounded
310/// @see separatorStyled
311/// @see separatorCharacter
312///
313/// 2つの要素間に視覚的な区切りを追加します。
314///
315/// ### Example
316///
317/// ```cpp
318/// // 関数として \'border\' を使用...
319/// Element document = vbox({
320/// text("up"),
321/// separatorCharacter("-"),
322/// text("down"),
323/// });
324///
325/// ### Output
326///
327/// ```bash
328/// up
329/// ────
330/// down
331/// ```
332Element separatorCharacter(std::string value) {
333 return std::make_shared<Separator>(std::move(value));
334}
335
336/// @brief 指定されたピクセルで埋められた2つの要素間に区切り線を描画します。
337/// @ingroup dom
338/// @see separator
339/// @see separatorLight
340/// @see separatorDashed
341/// @see separatorHeavy
342/// @see separatorDouble
343/// @see separatorStyled
344///
345/// ### 例
346///
347/// ```cpp
348/// Pixel empty;
349/// Element document = vbox({
350/// text("上"),
351/// separator(empty),
352/// text("下"),
353/// })
354/// ```
355///
356/// ### Output
357///
358/// ```bash
359/// Up
360///
361/// Down
362/// ```
363Element separator(Pixel pixel) {
364 return std::make_shared<SeparatorWithPixel>(std::move(pixel));
365}
366
367/// @brief 左右の領域が異なる色で表示される水平バーを描画します。
368/// @param left アクティブ領域の左端。
369/// @param right アクティブ領域の右端。
370/// @param selected_color 選択された領域の色。
371/// @param unselected_color 選択されていない領域の色。
372///
373/// ### 例
374///
375/// ```cpp
376/// Element document = separatorHSelector(2,5, Color::White, Color::Blue);
377/// ```
379 float right,
380 Color unselected_color,
381 Color selected_color) {
382 class Impl : public Node {
383 public:
384 Impl(float left, float right, Color selected_color, Color unselected_color)
385 : left_(left),
386 right_(right),
387 unselected_color_(unselected_color),
388 selected_color_(selected_color) {}
389 void ComputeRequirement() override {
390 requirement_.min_x = 1;
391 requirement_.min_y = 1;
392 }
393
394 void Render(Screen& screen) override {
395 if (box_.y_max < box_.y_min) {
396 return;
397 }
398
399 // This are the two location with an empty demi-cell.
400 int demi_cell_left = int(left_ * 2.F - 1.F); // NOLINT
401 int demi_cell_right = int(right_ * 2.F + 2.F); // NOLINT
402
403 const int y = box_.y_min;
404 for (int x = box_.x_min; x <= box_.x_max; ++x) {
405 Pixel& pixel = screen.PixelAt(x, y);
406
407 const int a = (x - box_.x_min) * 2;
408 const int b = a + 1;
409 const bool a_empty = demi_cell_left == a || demi_cell_right == a;
410 const bool b_empty = demi_cell_left == b || demi_cell_right == b;
411
412 if (!a_empty && !b_empty) {
413 pixel.character = "─";
414 pixel.automerge = true;
415 } else {
416 pixel.character = a_empty ? "╶" : "╴"; // NOLINT
417 pixel.automerge = false;
418 }
419
420 if (demi_cell_left <= a && b <= demi_cell_right) {
421 pixel.foreground_color = selected_color_;
422 } else {
423 pixel.foreground_color = unselected_color_;
424 }
425 }
426 }
427
428 float left_;
429 float right_;
430 Color unselected_color_;
431 Color selected_color_;
432 };
433 return std::make_shared<Impl>(left, right, unselected_color, selected_color);
434}
435
436/// @brief 上下の領域が異なる色で表示される垂直バーを描画します。
437/// @param up アクティブ領域の上端。
438/// @param down アクティブ領域の下端。
439/// @param selected_color 選択された領域の色。
440/// @param unselected_color 選択されていない領域の色。
441///
442/// ### 例
443///
444/// ```cpp
445/// Element document = separatorVSelector(2,5, Color::White, Color::Blue);
446/// ```
448 float down,
449 Color unselected_color,
450 Color selected_color) {
451 class Impl : public Node {
452 public:
453 Impl(float up, float down, Color unselected_color, Color selected_color)
454 : up_(up),
455 down_(down),
456 unselected_color_(unselected_color),
457 selected_color_(selected_color) {}
458 void ComputeRequirement() override {
459 requirement_.min_x = 1;
460 requirement_.min_y = 1;
461 }
462
463 void Render(Screen& screen) override {
464 if (box_.x_max < box_.x_min) {
465 return;
466 }
467
468 // This are the two location with an empty demi-cell.
469 const int demi_cell_up = int(up_ * 2 - 1);
470 const int demi_cell_down = int(down_ * 2 + 2);
471
472 const int x = box_.x_min;
473 for (int y = box_.y_min; y <= box_.y_max; ++y) {
474 Pixel& pixel = screen.PixelAt(x, y);
475
476 const int a = (y - box_.y_min) * 2;
477 const int b = a + 1;
478 const bool a_empty = demi_cell_up == a || demi_cell_down == a;
479 const bool b_empty = demi_cell_up == b || demi_cell_down == b;
480
481 if (!a_empty && !b_empty) {
482 pixel.character = "│";
483 pixel.automerge = true;
484 } else {
485 pixel.character = a_empty ? "╷" : "╵"; // NOLINT
486 pixel.automerge = false;
487 }
488
489 if (demi_cell_up <= a && b <= demi_cell_down) {
490 pixel.foreground_color = selected_color_;
491 } else {
492 pixel.foreground_color = unselected_color_;
493 }
494 }
495 }
496
497 float up_;
498 float down_;
499 Color unselected_color_;
500 Color selected_color_;
501 };
502 return std::make_shared<Impl>(up, down, unselected_color, selected_color);
503}
504
505} // namespace ftxui
Element separatorStyled(BorderStyle)
他の2つの要素の間に垂直または水平の区切り線を描画します。
Element separatorEmpty()
他の2つの要素の間にEMPTYスタイルで垂直または水平の区切り線を描画します。
Element separatorDashed()
他の2つの要素の間にLIGHTスタイルで垂直または水平の区切り線を描画します。
void Render(Screen &screen, const Element &element)
要素をftxui::Screenに表示します。
Definition node.cpp:84
Element separatorDouble()
他の2つの要素の間にHEAVYスタイルで垂直または水平の区切り線を描画します。
BorderStyle
BorderStyleは、ターミナルUIの要素に適用できる様々なボーダースタイルを表す列挙型です。
Definition elements.hpp:31
@ EMPTY
Definition elements.hpp:37
@ DOUBLE
Definition elements.hpp:35
@ HEAVY
Definition elements.hpp:34
@ DASHED
Definition elements.hpp:33
@ LIGHT
Definition elements.hpp:32
Color
Colorは、ターミナルの色サポートを表す列挙型です。
Definition terminal.hpp:21
FTXUI ftxui:: 名前空間
Definition animation.hpp:9
Element separatorVSelector(float up, float down, Color unselected_color, Color selected_color)
std::shared_ptr< Node > Element
Definition elements.hpp:21
Element separatorLight()
Element separatorHSelector(float left, float right, Color unselected_color, Color selected_color)
Element separatorCharacter(std::string)
Element separator()
Element separatorHeavy()
std::uint8_t left
Definition screen.cpp:129
std::uint8_t down
Definition screen.cpp:132
std::uint8_t right
Definition screen.cpp:131
std::function< void(Pixel &)> style_
std::string value_