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