FTXUI  5.0.0
C++ functional terminal UI.
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/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 = charsets[style_][int(is_line && !is_column)];
67
68 for (int y = box_.y_min; y <= box_.y_max; ++y) {
69 for (int x = box_.x_min; x <= box_.x_max; ++x) {
70 Pixel& pixel = screen.PixelAt(x, y);
71 pixel.character = c;
72 pixel.automerge = true;
73 }
74 }
75 }
76
77 BorderStyle style_;
78};
79
80class SeparatorWithPixel : public SeparatorAuto {
81 public:
82 explicit SeparatorWithPixel(Pixel pixel)
83 : SeparatorAuto(LIGHT), pixel_(std::move(pixel)) {
84 pixel_.automerge = true;
85 }
86 void Render(Screen& screen) override {
87 for (int y = box_.y_min; y <= box_.y_max; ++y) {
88 for (int x = box_.x_min; x <= box_.x_max; ++x) {
89 screen.PixelAt(x, y) = pixel_;
90 }
91 }
92 }
93
94 private:
95 Pixel pixel_;
96};
97} // namespace
98
99/// @brief Draw a vertical or horizontal separation in between two other
100/// elements.
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/// Add a visual separation in between two elements.
113///
114/// ### Example
115///
116/// ```cpp
117/// // Use 'border' as a function...
118/// Element document = vbox({
119/// text("up"),
120/// separator(),
121/// text("down"),
122/// });
123/// ```
124///
125/// ### Output
126///
127/// ```bash
128/// up
129/// ────
130/// down
131/// ```
133 return std::make_shared<SeparatorAuto>(LIGHT);
134}
135
136/// @brief Draw a vertical or horizontal separation in between two other
137/// elements.
138/// @param style the style of the separator.
139/// @ingroup dom
140/// @see separator
141/// @see separatorLight
142/// @see separatorDashed
143/// @see separatorDouble
144/// @see separatorHeavy
145/// @see separatorEmpty
146/// @see separatorRounded
147/// @see separatorStyled
148/// @see separatorCharacter
149///
150/// Add a visual separation in between two elements.
151///
152/// ### Example
153///
154/// ```cpp
155/// // Use 'border' as a function...
156/// Element document = vbox({
157/// text("up"),
158/// separatorStyled(DOUBLE),
159/// text("down"),
160/// });
161/// ```
162///
163/// ### Output
164///
165/// ```bash
166/// up
167/// ════
168/// down
169/// ```
171 return std::make_shared<SeparatorAuto>(style);
172}
173
174/// @brief Draw a vertical or horizontal separation in between two other
175/// elements, using the LIGHT style.
176/// @ingroup dom
177/// @see separator
178/// @see separatorLight
179/// @see separatorDashed
180/// @see separatorDouble
181/// @see separatorHeavy
182/// @see separatorEmpty
183/// @see separatorRounded
184/// @see separatorStyled
185/// @see separatorCharacter
186///
187/// Add a visual separation in between two elements.
188///
189/// ### Example
190///
191/// ```cpp
192/// // Use 'border' as a function...
193/// Element document = vbox({
194/// text("up"),
195/// separatorLight(),
196/// text("down"),
197/// });
198/// ```
199///
200/// ### Output
201///
202/// ```bash
203/// up
204/// ────
205/// down
206/// ```
208 return std::make_shared<SeparatorAuto>(LIGHT);
209}
210
211/// @brief Draw a vertical or horizontal separation in between two other
212/// elements, using the DASHED style.
213/// @ingroup dom
214/// @see separator
215/// @see separatorLight
216/// @see separatorDashed
217/// @see separatorDouble
218/// @see separatorHeavy
219/// @see separatorEmpty
220/// @see separatorRounded
221/// @see separatorStyled
222/// @see separatorCharacter
223///
224/// Add a visual separation in between two elements.
225///
226/// ### Example
227///
228/// ```cpp
229/// // Use 'border' as a function...
230/// Element document = vbox({
231/// text("up"),
232/// separatorLight(),
233/// text("down"),
234/// });
235/// ```
236///
237/// ### Output
238///
239/// ```bash
240/// up
241/// ╍╍╍╍
242/// down
243/// ```
245 return std::make_shared<SeparatorAuto>(DASHED);
246}
247
248/// @brief Draw a vertical or horizontal separation in between two other
249/// elements, using the HEAVY style.
250/// @ingroup dom
251/// @see separator
252/// @see separatorLight
253/// @see separatorDashed
254/// @see separatorDouble
255/// @see separatorHeavy
256/// @see separatorEmpty
257/// @see separatorRounded
258/// @see separatorStyled
259/// @see separatorCharacter
260///
261/// Add a visual separation in between two elements.
262///
263/// ### Example
264///
265/// ```cpp
266/// // Use 'border' as a function...
267/// Element document = vbox({
268/// text("up"),
269/// separatorHeavy(),
270/// text("down"),
271/// });
272/// ```
273///
274/// ### Output
275///
276/// ```bash
277/// up
278/// ━━━━
279/// down
280/// ```
282 return std::make_shared<SeparatorAuto>(HEAVY);
283}
284
285/// @brief Draw a vertical or horizontal separation in between two other
286/// elements, using the DOUBLE style.
287/// @ingroup dom
288/// @see separator
289/// @see separatorLight
290/// @see separatorDashed
291/// @see separatorDouble
292/// @see separatorHeavy
293/// @see separatorEmpty
294/// @see separatorRounded
295/// @see separatorStyled
296/// @see separatorCharacter
297///
298/// Add a visual separation in between two elements.
299///
300/// ### Example
301///
302/// ```cpp
303/// // Use 'border' as a function...
304/// Element document = vbox({
305/// text("up"),
306/// separatorDouble(),
307/// text("down"),
308/// });
309/// ```
310///
311/// ### Output
312///
313/// ```bash
314/// up
315/// ════
316/// down
317/// ```
319 return std::make_shared<SeparatorAuto>(DOUBLE);
320}
321
322/// @brief Draw a vertical or horizontal separation in between two other
323/// elements, using the EMPTY style.
324/// @ingroup dom
325/// @see separator
326/// @see separatorLight
327/// @see separatorDashed
328/// @see separatorDouble
329/// @see separatorHeavy
330/// @see separatorEmpty
331/// @see separatorRounded
332/// @see separatorStyled
333/// @see separatorCharacter
334///
335/// Add a visual separation in between two elements.
336///
337/// ### Example
338///
339/// ```cpp
340/// // Use 'border' as a function...
341/// Element document = vbox({
342/// text("up"),
343/// separator(),
344/// text("down"),
345/// });
346/// ```
347///
348/// ### Output
349///
350/// ```bash
351/// up
352///
353/// down
354/// ```
356 return std::make_shared<SeparatorAuto>(EMPTY);
357}
358
359/// @brief Draw a vertical or horizontal separation in between two other
360/// elements.
361/// @param value the character to fill the separator area.
362/// @ingroup dom
363/// @see separator
364/// @see separatorLight
365/// @see separatorDashed
366/// @see separatorDouble
367/// @see separatorHeavy
368/// @see separatorEmpty
369/// @see separatorRounded
370/// @see separatorStyled
371/// @see separatorCharacter
372///
373/// Add a visual separation in between two elements.
374///
375/// ### Example
376///
377/// ```cpp
378/// // Use 'border' as a function...
379/// Element document = vbox({
380/// text("up"),
381/// separator(),
382/// text("down"),
383/// });
384/// ```
385///
386/// ### Output
387///
388/// ```bash
389/// up
390/// ────
391/// down
392/// ```
393Element separatorCharacter(std::string value) {
394 return std::make_shared<Separator>(std::move(value));
395}
396
397/// @brief Draw a separator in between two element filled with a given pixel.
398/// @ingroup dom
399/// @see separator
400/// @see separatorLight
401/// @see separatorDashed
402/// @see separatorHeavy
403/// @see separatorDouble
404/// @see separatorStyled
405///
406/// ### Example
407///
408/// ```cpp
409/// Pixel empty;
410/// Element document = vbox({
411/// text("Up"),
412/// separator(empty),
413/// text("Down"),
414/// })
415/// ```
416///
417/// ### Output
418///
419/// ```bash
420/// Up
421///
422/// Down
423/// ```
425 return std::make_shared<SeparatorWithPixel>(std::move(pixel));
426}
427
428/// @brief Draw an horizontal bar, with the area in between left/right colored
429/// differently.
430/// @param left the left limit of the active area.
431/// @param right the right limit of the active area.
432/// @param selected_color the color of the selected area.
433/// @param unselected_color the color of the unselected area.
434///
435/// ### Example
436///
437/// ```cpp
438/// Element document = separatorHSelector(2,5, Color::White, Color::Blue);
439/// ```
441 float right,
442 Color unselected_color,
443 Color selected_color) {
444 class Impl : public Node {
445 public:
446 Impl(float left, float right, Color selected_color, Color unselected_color)
447 : left_(left),
448 right_(right),
449 unselected_color_(unselected_color),
450 selected_color_(selected_color) {}
451 void ComputeRequirement() override {
452 requirement_.min_x = 1;
453 requirement_.min_y = 1;
454 }
455
456 void Render(Screen& screen) override {
457 if (box_.y_max < box_.y_min) {
458 return;
459 }
460
461 // This are the two location with an empty demi-cell.
462 int demi_cell_left = int(left_ * 2.F - 1.F); // NOLINT
463 int demi_cell_right = int(right_ * 2.F + 2.F); // NOLINT
464
465 const int y = box_.y_min;
466 for (int x = box_.x_min; x <= box_.x_max; ++x) {
467 Pixel& pixel = screen.PixelAt(x, y);
468
469 const int a = (x - box_.x_min) * 2;
470 const int b = a + 1;
471 const bool a_empty = demi_cell_left == a || demi_cell_right == a;
472 const bool b_empty = demi_cell_left == b || demi_cell_right == b;
473
474 if (!a_empty && !b_empty) {
475 pixel.character = "─";
476 pixel.automerge = true;
477 } else {
478 pixel.character = a_empty ? "╶" : "╴"; // NOLINT
479 pixel.automerge = false;
480 }
481
482 if (demi_cell_left <= a && b <= demi_cell_right) {
483 pixel.foreground_color = selected_color_;
484 } else {
485 pixel.foreground_color = unselected_color_;
486 }
487 }
488 }
489
490 float left_;
491 float right_;
492 Color unselected_color_;
493 Color selected_color_;
494 };
495 return std::make_shared<Impl>(left, right, unselected_color, selected_color);
496}
497
498/// @brief Draw an vertical bar, with the area in between up/downcolored
499/// differently.
500/// @param up the left limit of the active area.
501/// @param down the right limit of the active area.
502/// @param selected_color the color of the selected area.
503/// @param unselected_color the color of the unselected area.
504///
505/// ### Example
506///
507/// ```cpp
508/// Element document = separatorHSelector(2,5, Color::White, Color::Blue);
509/// ```
511 float down,
512 Color unselected_color,
513 Color selected_color) {
514 class Impl : public Node {
515 public:
516 Impl(float up, float down, Color unselected_color, Color selected_color)
517 : up_(up),
518 down_(down),
519 unselected_color_(unselected_color),
520 selected_color_(selected_color) {}
521 void ComputeRequirement() override {
522 requirement_.min_x = 1;
523 requirement_.min_y = 1;
524 }
525
526 void Render(Screen& screen) override {
527 if (box_.x_max < box_.x_min) {
528 return;
529 }
530
531 // This are the two location with an empty demi-cell.
532 const int demi_cell_up = int(up_ * 2 - 1);
533 const int demi_cell_down = int(down_ * 2 + 2);
534
535 const int x = box_.x_min;
536 for (int y = box_.y_min; y <= box_.y_max; ++y) {
537 Pixel& pixel = screen.PixelAt(x, y);
538
539 const int a = (y - box_.y_min) * 2;
540 const int b = a + 1;
541 const bool a_empty = demi_cell_up == a || demi_cell_down == a;
542 const bool b_empty = demi_cell_up == b || demi_cell_down == b;
543
544 if (!a_empty && !b_empty) {
545 pixel.character = "│";
546 pixel.automerge = true;
547 } else {
548 pixel.character = a_empty ? "╷" : "╵"; // NOLINT
549 pixel.automerge = false;
550 }
551
552 if (demi_cell_up <= a && b <= demi_cell_down) {
553 pixel.foreground_color = selected_color_;
554 } else {
555 pixel.foreground_color = unselected_color_;
556 }
557 }
558 }
559
560 float up_;
561 float down_;
562 Color unselected_color_;
563 Color selected_color_;
564 };
565 return std::make_shared<Impl>(up, down, unselected_color, selected_color);
566}
567
568} // namespace ftxui
A class representing terminal colors.
Definition: color.hpp:21
A rectangular grid of Pixel.
Definition: screen.hpp:63
Pixel & PixelAt(int x, int y)
Access a cell (Pixel) at a given position.
Definition: screen.cpp:470
Element separatorStyled(BorderStyle)
Draw a vertical or horizontal separation in between two other elements.
Definition: separator.cpp:170
Element separatorEmpty()
Draw a vertical or horizontal separation in between two other elements, using the EMPTY style.
Definition: separator.cpp:355
Element separatorVSelector(float up, float down, Color unselected_color, Color selected_color)
Draw an vertical bar, with the area in between up/downcolored differently.
Definition: separator.cpp:510
std::shared_ptr< Node > Element
Definition: elements.hpp:23
Element separatorLight()
Draw a vertical or horizontal separation in between two other elements, using the LIGHT style.
Definition: separator.cpp:207
Element separatorHSelector(float left, float right, Color unselected_color, Color selected_color)
Draw an horizontal bar, with the area in between left/right colored differently.
Definition: separator.cpp:440
Element separatorDashed()
Draw a vertical or horizontal separation in between two other elements, using the DASHED style.
Definition: separator.cpp:244
Element separatorCharacter(std::string)
Draw a vertical or horizontal separation in between two other elements.
Definition: separator.cpp:393
Element separator()
Draw a vertical or horizontal separation in between two other elements.
Definition: separator.cpp:132
void Render(Screen &screen, const Element &element)
Display an element on a ftxui::Screen.
Definition: node.cpp:47
Element separatorDouble()
Draw a vertical or horizontal separation in between two other elements, using the DOUBLE style.
Definition: separator.cpp:318
Element separatorHeavy()
Draw a vertical or horizontal separation in between two other elements, using the HEAVY style.
Definition: separator.cpp:281
BorderStyle
Definition: elements.hpp:28
@ EMPTY
Definition: elements.hpp:34
@ DOUBLE
Definition: elements.hpp:32
@ HEAVY
Definition: elements.hpp:31
@ DASHED
Definition: elements.hpp:30
@ LIGHT
Definition: elements.hpp:29
A unicode character and its associated style.
Definition: screen.hpp:20
Color foreground_color
Definition: screen.hpp:51
std::string character
Definition: screen.hpp:47
bool automerge
Definition: screen.hpp:39