FTXUI 6.1.9 C++ functional terminal UI.

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