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