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