FTXUI  5.0.0
C++ functional terminal UI.
Loading...
Searching...
No Matches
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
79 BorderStyle style_;
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 an 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,
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),
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_;
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,
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),
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_;
566 };
567 return std::make_shared<Impl>(up, down, unselected_color, selected_color);
568}
569
570} // namespace ftxui
A class representing terminal colors.
Definition color.hpp:20
A rectangular grid of Pixel.
Definition screen.hpp:25
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 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
std::shared_ptr< T > Make(Args &&... args)
Definition component.hpp:26
Element separatorLight()
Draw a vertical or horizontal separation in between two other elements, using the LIGHT style.
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.
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:47
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
Definition elements.hpp:27
@ EMPTY
Definition elements.hpp:33
@ DOUBLE
Definition elements.hpp:31
@ HEAVY
Definition elements.hpp:30
@ DASHED
Definition elements.hpp:29
@ LIGHT
Definition elements.hpp:28
A Unicode character and its associated style.
Definition pixel.hpp:15
std::string character
Definition pixel.hpp:43