FTXUI  4.1.1
C++ functional terminal UI.
Loading...
Searching...
No Matches
border.cpp
Go to the documentation of this file.
1#include <algorithm> // for max
2#include <array> // for array
3#include <ftxui/screen/color.hpp> // for Color
4#include <memory> // for allocator, make_shared, __shared_ptr_access
5#include <optional> // for optional, nullopt
6#include <string> // for basic_string, string
7#include <utility> // for move
8#include <vector> // for __alloc_traits<>::value_type
9
10#include "ftxui/dom/elements.hpp" // for unpack, Element, Decorator, BorderStyle, ROUNDED, borderStyled, Elements, DASHED, DOUBLE, EMPTY, HEAVY, LIGHT, border, borderDashed, borderDouble, borderEmpty, borderHeavy, borderLight, borderRounded, borderWith, window
11#include "ftxui/dom/node.hpp" // for Node, Elements
12#include "ftxui/dom/requirement.hpp" // for Requirement
13#include "ftxui/screen/box.hpp" // for Box
14#include "ftxui/screen/screen.hpp" // for Pixel, Screen
15
16namespace ftxui {
17
18using Charset = std::array<std::string, 6>; // NOLINT
19using Charsets = std::array<Charset, 6>; // NOLINT
20// NOLINTNEXTLINE
21static Charsets simple_border_charset = {
22 Charset{"┌", "┐", "└", "┘", "─", "│"}, // LIGHT
23 Charset{"┏", "┓", "┗", "┛", "╍", "╏"}, // DASHED
24 Charset{"┏", "┓", "┗", "┛", "━", "┃"}, // HEAVY
25 Charset{"╔", "╗", "╚", "╝", "═", "║"}, // DOUBLE
26 Charset{"╭", "╮", "╰", "╯", "─", "│"}, // ROUNDED
27 Charset{" ", " ", " ", " ", " ", " "}, // EMPTY
28};
29
30// For reference, here is the charset for normal border:
31class Border : public Node {
32 public:
33 Border(Elements children,
34 BorderStyle style,
35 std::optional<Color> foreground_color = std::nullopt)
36 : Node(std::move(children)),
37 charset_(simple_border_charset[style]),
38 foreground_color_(foreground_color) {} // NOLINT
39
40 const Charset& charset_; // NOLINT
41 std::optional<Color> foreground_color_;
42
43 void ComputeRequirement() override {
45 requirement_ = children_[0]->requirement();
48 if (children_.size() == 2) {
50 std::max(requirement_.min_x, children_[1]->requirement().min_x + 2);
51 }
56 }
57
58 void SetBox(Box box) override {
59 Node::SetBox(box);
60 if (children_.size() == 2) {
61 Box title_box;
62 title_box.x_min = box.x_min + 1;
63 title_box.x_max = box.x_max - 1;
64 title_box.y_min = box.y_min;
65 title_box.y_max = box.y_min;
66 children_[1]->SetBox(title_box);
67 }
68 box.x_min++;
69 box.x_max--;
70 box.y_min++;
71 box.y_max--;
72 children_[0]->SetBox(box);
73 }
74
75 void Render(Screen& screen) override {
76 // Draw content.
77 children_[0]->Render(screen);
78
79 // Draw the border.
80 if (box_.x_min >= box_.x_max || box_.y_min >= box_.y_max) {
81 return;
82 }
83
84 screen.at(box_.x_min, box_.y_min) = charset_[0]; // NOLINT
85 screen.at(box_.x_max, box_.y_min) = charset_[1]; // NOLINT
86 screen.at(box_.x_min, box_.y_max) = charset_[2]; // NOLINT
87 screen.at(box_.x_max, box_.y_max) = charset_[3]; // NOLINT
88
89 for (int x = box_.x_min + 1; x < box_.x_max; ++x) {
90 Pixel& p1 = screen.PixelAt(x, box_.y_min);
91 Pixel& p2 = screen.PixelAt(x, box_.y_max);
92 p1.character = charset_[4]; // NOLINT
93 p2.character = charset_[4]; // NOLINT
94 p1.automerge = true;
95 p2.automerge = true;
96 }
97 for (int y = box_.y_min + 1; y < box_.y_max; ++y) {
98 Pixel& p3 = screen.PixelAt(box_.x_min, y);
99 Pixel& p4 = screen.PixelAt(box_.x_max, y);
100 p3.character = charset_[5]; // NOLINT
101 p4.character = charset_[5]; // NOLINT
102 p3.automerge = true;
103 p4.automerge = true;
104 }
105
106 // Draw title.
107 if (children_.size() == 2) {
108 children_[1]->Render(screen);
109 }
110
111 // Draw the border color.
112 if (foreground_color_) {
113 for (int x = box_.x_min; x <= box_.x_max; ++x) {
114 screen.PixelAt(x, box_.y_min).foreground_color = *foreground_color_;
115 screen.PixelAt(x, box_.y_max).foreground_color = *foreground_color_;
116 }
117 for (int y = box_.y_min; y <= box_.y_max; ++y) {
118 screen.PixelAt(box_.x_min, y).foreground_color = *foreground_color_;
119 screen.PixelAt(box_.x_max, y).foreground_color = *foreground_color_;
120 }
121 }
122 }
123};
124
125// For reference, here is the charset for normal border:
126class BorderPixel : public Node {
127 public:
128 BorderPixel(Elements children, Pixel pixel)
129 : Node(std::move(children)), pixel_(std::move(pixel)) {}
130
131 private:
132 Pixel pixel_;
133
134 void ComputeRequirement() override {
136 requirement_ = children_[0]->requirement();
137 requirement_.min_x += 2;
138 requirement_.min_y += 2;
139 if (children_.size() == 2) {
141 std::max(requirement_.min_x, children_[1]->requirement().min_x + 2);
142 }
147 }
148
149 void SetBox(Box box) override {
150 Node::SetBox(box);
151 if (children_.size() == 2) {
152 Box title_box;
153 title_box.x_min = box.x_min + 1;
154 title_box.x_max = box.x_max - 1;
155 title_box.y_min = box.y_min;
156 title_box.y_max = box.y_min;
157 children_[1]->SetBox(title_box);
158 }
159 box.x_min++;
160 box.x_max--;
161 box.y_min++;
162 box.y_max--;
163 children_[0]->SetBox(box);
164 }
165
166 void Render(Screen& screen) override {
167 // Draw content.
168 children_[0]->Render(screen);
169
170 // Draw the border.
171 if (box_.x_min >= box_.x_max || box_.y_min >= box_.y_max) {
172 return;
173 }
174
175 screen.PixelAt(box_.x_min, box_.y_min) = pixel_;
176 screen.PixelAt(box_.x_max, box_.y_min) = pixel_;
177 screen.PixelAt(box_.x_min, box_.y_max) = pixel_;
178 screen.PixelAt(box_.x_max, box_.y_max) = pixel_;
179
180 for (int x = box_.x_min + 1; x < box_.x_max; ++x) {
181 screen.PixelAt(x, box_.y_min) = pixel_;
182 screen.PixelAt(x, box_.y_max) = pixel_;
183 }
184 for (int y = box_.y_min + 1; y < box_.y_max; ++y) {
185 screen.PixelAt(box_.x_min, y) = pixel_;
186 screen.PixelAt(box_.x_max, y) = pixel_;
187 }
188 }
189};
190
191/// @brief Draw a border around the element.
192/// @ingroup dom
193/// @see border
194/// @see borderLight
195/// @see borderDashed
196/// @see borderDouble
197/// @see borderHeavy
198/// @see borderEmpty
199/// @see borderRounded
200/// @see borderStyled
201/// @see borderWith
202///
203/// Add a border around an element
204///
205/// ### Example
206///
207/// ```cpp
208/// // Use 'border' as a function...
209/// Element document = border(text("The element"));
210///
211/// // ...Or as a 'pipe'.
212/// Element document = text("The element") | border;
213/// ```
214///
215/// ### Output
216///
217/// ```bash
218/// ┌───────────┐
219/// │The element│
220/// └───────────┘
221/// ```
223 return std::make_shared<Border>(unpack(std::move(child)), ROUNDED);
224}
225
226/// @brief Same as border but with a constant Pixel around the element.
227/// @ingroup dom
228/// @see border
230 return [pixel](Element child) {
231 return std::make_shared<BorderPixel>(unpack(std::move(child)), pixel);
232 };
233}
234
235/// @brief Same as border but with different styles.
236/// @ingroup dom
237/// @see border
239 return [style](Element child) {
240 return std::make_shared<Border>(unpack(std::move(child)), style);
241 };
242}
243
244/// @brief Same as border but with a foreground color.
245/// @ingroup dom
246/// @see border
247Decorator borderStyled(Color foreground_color) {
248 return [foreground_color](Element child) {
249 return std::make_shared<Border>(unpack(std::move(child)), ROUNDED,
250 foreground_color);
251 };
252}
253
254/// @brief Same as border but with a foreground color and a different style
255/// @ingroup dom
256/// @see border
257Decorator borderStyled(BorderStyle style, Color foreground_color) {
258 return [style, foreground_color](Element child) {
259 return std::make_shared<Border>(unpack(std::move(child)), style,
260 foreground_color);
261 };
262}
263
264/// @brief Draw a light border around the element.
265/// @ingroup dom
266/// @see border
267/// @see borderLight
268/// @see borderDashed
269/// @see borderDouble
270/// @see borderHeavy
271/// @see borderRounded
272/// @see borderEmpty
273/// @see borderStyled
274/// @see borderWith
275///
276/// Add a border around an element
277///
278/// ### Example
279///
280/// ```cpp
281/// // Use 'borderDash' as a function...
282/// Element document = borderDash(text("The element"));
283///
284/// // ...Or as a 'pipe'.
285/// Element document = text("The element") | borderDAsh;
286/// ```
287///
288/// ### Output
289///
290/// ```bash
291/// ┏╍╍╍╍╍╍╍╍╍╍╍╍╍╍┓
292/// ╏The element ╏
293/// ┗╍╍╍╍╍╍╍╍╍╍╍╍╍╍┛
294/// ```
296 return std::make_shared<Border>(unpack(std::move(child)), DASHED);
297}
298
299/// @brief Draw a dashed border around the element.
300/// @ingroup dom
301/// @see border
302/// @see borderLight
303/// @see borderDashed
304/// @see borderDouble
305/// @see borderHeavy
306/// @see borderRounded
307/// @see borderEmpty
308/// @see borderStyled
309/// @see borderWith
310///
311/// Add a border around an element
312///
313/// ### Example
314///
315/// ```cpp
316/// // Use 'borderLight' as a function...
317/// Element document = borderLight(text("The element"));
318///
319/// // ...Or as a 'pipe'.
320/// Element document = text("The element") | borderLight;
321/// ```
322///
323/// ### Output
324///
325/// ```bash
326/// ┌──────────────┐
327/// │The element │
328/// └──────────────┘
329/// ```
331 return std::make_shared<Border>(unpack(std::move(child)), LIGHT);
332}
333
334/// @brief Draw a heavy border around the element.
335/// @ingroup dom
336/// @see border
337/// @see borderLight
338/// @see borderDashed
339/// @see borderDouble
340/// @see borderHeavy
341/// @see borderRounded
342/// @see borderEmpty
343/// @see borderStyled
344/// @see borderWith
345///
346/// Add a border around an element
347///
348/// ### Example
349///
350/// ```cpp
351/// // Use 'borderHeavy' as a function...
352/// Element document = borderHeavy(text("The element"));
353///
354/// // ...Or as a 'pipe'.
355/// Element document = text("The element") | borderHeavy;
356/// ```
357///
358/// ### Output
359///
360/// ```bash
361/// ┏━━━━━━━━━━━━━━┓
362/// ┃The element ┃
363/// ┗━━━━━━━━━━━━━━┛
364/// ```
366 return std::make_shared<Border>(unpack(std::move(child)), HEAVY);
367}
368
369/// @brief Draw a double border around the element.
370/// @ingroup dom
371/// @see border
372/// @see borderLight
373/// @see borderDashed
374/// @see borderDouble
375/// @see borderHeavy
376/// @see borderRounded
377/// @see borderEmpty
378/// @see borderStyled
379/// @see borderWith
380///
381/// Add a border around an element
382///
383/// ### Example
384///
385/// ```cpp
386/// // Use 'borderDouble' as a function...
387/// Element document = borderDouble(text("The element"));
388///
389/// // ...Or as a 'pipe'.
390/// Element document = text("The element") | borderDouble;
391/// ```
392///
393/// ### Output
394///
395/// ```bash
396/// ╔══════════════╗
397/// ║The element ║
398/// ╚══════════════╝
399/// ```
401 return std::make_shared<Border>(unpack(std::move(child)), DOUBLE);
402}
403
404/// @brief Draw a rounded border around the element.
405/// @ingroup dom
406/// @see border
407/// @see borderLight
408/// @see borderDashed
409/// @see borderDouble
410/// @see borderHeavy
411/// @see borderRounded
412/// @see borderEmpty
413/// @see borderStyled
414/// @see borderWith
415///
416/// Add a border around an element
417///
418/// ### Example
419///
420/// ```cpp
421/// // Use 'borderRounded' as a function...
422/// Element document = borderRounded(text("The element"));
423///
424/// // ...Or as a 'pipe'.
425/// Element document = text("The element") | borderRounded;
426/// ```
427///
428/// ### Output
429///
430/// ```bash
431/// ╭──────────────╮
432/// │The element │
433/// ╰──────────────╯
434/// ```
436 return std::make_shared<Border>(unpack(std::move(child)), ROUNDED);
437}
438
439/// @brief Draw an empty border around the element.
440/// @ingroup dom
441/// @see border
442/// @see borderLight
443/// @see borderDashed
444/// @see borderDouble
445/// @see borderHeavy
446/// @see borderRounded
447/// @see borderEmpty
448/// @see borderStyled
449/// @see borderWith
450///
451/// Add a border around an element
452///
453/// ### Example
454///
455/// ```cpp
456/// // Use 'borderRounded' as a function...
457/// Element document = borderRounded(text("The element"));
458///
459/// // ...Or as a 'pipe'.
460/// Element document = text("The element") | borderRounded;
461/// ```
462///
463/// ### Output
464///
465/// ```bash
466///
467/// The element
468///
469/// ```
471 return std::make_shared<Border>(unpack(std::move(child)), EMPTY);
472}
473
474/// @brief Draw window with a title and a border around the element.
475/// @param title The title of the window.
476/// @param content The element to be wrapped.
477/// @ingroup dom
478/// @see border
479///
480/// ### Example
481///
482/// ```cpp
483/// Element document = window(text("Title"),
484/// text("content")
485/// );
486/// ```
487///
488/// ### Output
489///
490/// ```bash
491/// ┌Title──┐
492/// │content│
493/// └───────┘
494/// ```
495Element window(Element title, Element content) {
496 return std::make_shared<Border>(unpack(std::move(content), std::move(title)),
497 ROUNDED);
498}
499} // namespace ftxui
500
501// Copyright 2020 Arthur Sonzogni. All rights reserved.
502// Use of this source code is governed by the MIT license that can be found in
503// the LICENSE file.
A class representing terminal colors.
Definition color.hpp:18
Elements children_
Definition node.hpp:53
virtual void SetBox(Box box)
Assign a position and a dimension to an element for drawing.
Definition node.cpp:23
Requirement requirement_
Definition node.hpp:54
virtual void ComputeRequirement()
Compute how much space an elements needs.
Definition node.cpp:15
Box box_
Definition node.hpp:55
Element borderDouble(Element)
Draw a double border around the element.
Definition border.cpp:400
std::function< Element(Element)> Decorator
Definition elements.hpp:21
Element borderDashed(Element)
Draw a light border around the element.
Definition border.cpp:295
std::shared_ptr< Node > Element
Definition elements.hpp:19
Element borderRounded(Element)
Draw a rounded border around the element.
Definition border.cpp:435
Element window(Element title, Element content)
Draw window with a title and a border around the element.
Definition border.cpp:495
std::vector< Element > Elements
Definition elements.hpp:20
std::array< Charset, 6 > Charsets
Definition border.cpp:19
Element borderHeavy(Element)
Draw a heavy border around the element.
Definition border.cpp:365
Element borderLight(Element)
Draw a dashed border around the element.
Definition border.cpp:330
Decorator borderWith(const Pixel &)
Same as border but with a constant Pixel around the element.
Definition border.cpp:229
Decorator borderStyled(BorderStyle)
Same as border but with different styles.
Definition border.cpp:238
std::array< std::string, 6 > Charset
Definition border.cpp:18
Element border(Element)
Draw a border around the element.
Definition border.cpp:222
Element borderEmpty(Element)
Draw an empty border around the element.
Definition border.cpp:470
BorderStyle
Definition elements.hpp:24
@ EMPTY
Definition elements.hpp:30
@ DOUBLE
Definition elements.hpp:28
@ HEAVY
Definition elements.hpp:27
@ ROUNDED
Definition elements.hpp:29
@ DASHED
Definition elements.hpp:26
@ LIGHT
Definition elements.hpp:25
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