FTXUI  2.0.0
C++ functional terminal UI.
Loading...
Searching...
No Matches
border.cpp
Go to the documentation of this file.
1#include <algorithm> // for max
2#include <iterator> // for begin, end
3#include <memory> // for allocator, make_shared, __shared_ptr_access
4#include <string> // for string, basic_string
5#include <utility> // for move
6#include <vector> // for vector, __alloc_traits<>::value_type
7
8#include "ftxui/dom/elements.hpp" // for unpack, Element, Decorator, BorderStyle, ROUNDED, Elements, DOUBLE, EMPTY, HEAVY, LIGHT, border, borderDouble, borderEmpty, borderHeavy, borderLight, borderRounded, borderStyled, borderWith, window
9#include "ftxui/dom/node.hpp" // for Node, Elements
10#include "ftxui/dom/requirement.hpp" // for Requirement
11#include "ftxui/screen/box.hpp" // for Box
12#include "ftxui/screen/screen.hpp" // for Pixel, Screen
13
14namespace ftxui {
15
16static std::string simple_border_charset[6][6] = {
17 {"┌", "┐", "└", "┘", "─", "│"}, //
18 {"┏", "┓", "┗", "┛", "━", "┃"}, //
19 {"╔", "╗", "╚", "╝", "═", "║"}, //
20 {"╭", "╮", "╰", "╯", "─", "│"}, //
21 {" ", " ", " ", " ", " ", " "}, //
22};
23
24// For reference, here is the charset for normal border:
25// {"┌", "┐", "└", "┘", "─", "│", "┬", "┴", "┤", "├"};
26// TODO(arthursonzogni): Consider adding options to choose the kind of borders
27// to use.
28
29class Border : public Node {
30 public:
31 Border(Elements children, BorderStyle style)
32 : Node(std::move(children)),
33 charset(std::begin(simple_border_charset[style]),
34 std::end(simple_border_charset[style])) {}
35 Border(Elements children, Pixel pixel)
36 : Node(std::move(children)), charset_pixel(10, pixel) {}
37
38 std::vector<Pixel> charset_pixel;
39 std::vector<std::string> charset;
40
41 void ComputeRequirement() override {
43 requirement_ = children_[0]->requirement();
46 if (children_.size() == 2) {
48 std::max(requirement_.min_x, children_[1]->requirement().min_x + 2);
49 }
54 }
55
56 void SetBox(Box box) override {
57 Node::SetBox(box);
58 if (children_.size() == 2) {
59 Box title_box;
60 title_box.x_min = box.x_min + 1;
61 title_box.x_max = box.x_max - 1;
62 title_box.y_min = box.y_min;
63 title_box.y_max = box.y_min;
64 children_[1]->SetBox(title_box);
65 }
66 box.x_min++;
67 box.x_max--;
68 box.y_min++;
69 box.y_max--;
70 children_[0]->SetBox(box);
71 }
72
73 void Render(Screen& screen) override {
74 // Draw content.
75 children_[0]->Render(screen);
76
77 // Draw the border.
78 if (box_.x_min >= box_.x_max || box_.y_min >= box_.y_max)
79 return;
80
81 if (!charset.empty())
82 RenderPixel(screen);
83 else
84 RenderChar(screen);
85 }
86
87 void RenderPixel(Screen& screen) {
88 screen.at(box_.x_min, box_.y_min) = charset[0];
89 screen.at(box_.x_max, box_.y_min) = charset[1];
90 screen.at(box_.x_min, box_.y_max) = charset[2];
91 screen.at(box_.x_max, box_.y_max) = charset[3];
92
93 for (float x = box_.x_min + 1; x < box_.x_max; ++x) {
94 Pixel& p1 = screen.PixelAt(x, box_.y_min);
95 Pixel& p2 = screen.PixelAt(x, box_.y_max);
96 p1.character = charset[4];
97 p2.character = charset[4];
98 p1.automerge = true;
99 p2.automerge = true;
100 }
101 for (float y = box_.y_min + 1; y < box_.y_max; ++y) {
102 Pixel& p3 = screen.PixelAt(box_.x_min, y);
103 Pixel& p4 = screen.PixelAt(box_.x_max, y);
104 p3.character = charset[5];
105 p4.character = charset[5];
106 p3.automerge = true;
107 p4.automerge = true;
108 }
109
110 // Draw title.
111 if (children_.size() == 2)
112 children_[1]->Render(screen);
113 }
114
115 void RenderChar(Screen& screen) {
116 screen.PixelAt(box_.x_min, box_.y_min) = charset_pixel[0];
117 screen.PixelAt(box_.x_max, box_.y_min) = charset_pixel[1];
118 screen.PixelAt(box_.x_min, box_.y_max) = charset_pixel[2];
119 screen.PixelAt(box_.x_max, box_.y_max) = charset_pixel[3];
120 for (float x = box_.x_min + 1; x < box_.x_max; ++x) {
121 Pixel& p1 = screen.PixelAt(x, box_.y_min);
122 Pixel& p2 = screen.PixelAt(x, box_.y_max);
123 p1 = charset_pixel[5];
124 p2 = charset_pixel[5];
125 p1.automerge = true;
126 p2.automerge = true;
127 }
128 for (float y = box_.y_min + 1; y < box_.y_max; ++y) {
129 Pixel& p3 = screen.PixelAt(box_.x_min, y);
130 Pixel& p4 = screen.PixelAt(box_.x_max, y);
131 p3 = charset_pixel[5];
132 p4 = charset_pixel[5];
133 p3.automerge = true;
134 p4.automerge = true;
135 }
136 }
137};
138
139/// @brief Draw a border around the element.
140/// @ingroup dom
141/// @see border
142/// @see borderLight
143/// @see borderDouble
144/// @see borderHeavy
145/// @see borderEmpty
146/// @see borderRounded
147///
148/// Add a border around an element
149///
150/// ### Example
151///
152/// ```cpp
153/// // Use 'border' as a function...
154/// Element document = border(text("The element"));
155///
156/// // ...Or as a 'pipe'.
157/// Element document = text("The element") | border;
158/// ```
159///
160/// ### Output
161///
162/// ```bash
163/// ┌───────────┐
164/// │The element│
165/// └───────────┘
166/// ```
168 return std::make_shared<Border>(unpack(std::move(child)), ROUNDED);
169}
170
171/// @brief Same as border but with a constant Pixel around the element.
172/// @ingroup dom
173/// @see border
175 return [pixel](Element child) {
176 return std::make_shared<Border>(unpack(std::move(child)), pixel);
177 };
178}
179
180/// @brief Same as border but with different styles.
181/// @ingroup dom
182/// @see border
184 return [style](Element child) {
185 return std::make_shared<Border>(unpack(std::move(child)), style);
186 };
187}
188
189/// @brief Draw a light border around the element.
190/// @ingroup dom
191/// @see border
192/// @see borderLight
193/// @see borderDouble
194/// @see borderHeavy
195/// @see borderRounded
196/// @see borderEmpty
197/// @see borderStyled
198/// @see borderWith
199///
200/// Add a border around an element
201///
202/// ### Example
203///
204/// ```cpp
205/// // Use 'borderLight' as a function...
206/// Element document = borderLight(text("The element"));
207///
208/// // ...Or as a 'pipe'.
209/// Element document = text("The element") | borderLight;
210/// ```
211///
212/// ### Output
213///
214/// ```bash
215/// ┌──────────────┐
216/// │The element │
217/// └──────────────┘
218/// ```
220 return std::make_shared<Border>(unpack(std::move(child)), LIGHT);
221}
222
223/// @brief Draw a heavy border around the element.
224/// @ingroup dom
225/// @see border
226/// @see borderLight
227/// @see borderDouble
228/// @see borderHeavy
229/// @see borderRounded
230/// @see borderEmpty
231/// @see borderStyled
232/// @see borderWith
233///
234/// Add a border around an element
235///
236/// ### Example
237///
238/// ```cpp
239/// // Use 'borderHeavy' as a function...
240/// Element document = borderHeavy(text("The element"));
241///
242/// // ...Or as a 'pipe'.
243/// Element document = text("The element") | borderHeavy;
244/// ```
245///
246/// ### Output
247///
248/// ```bash
249/// ┏━━━━━━━━━━━━━━┓
250/// ┃The element ┃
251/// ┗━━━━━━━━━━━━━━┛
252/// ```
254 return std::make_shared<Border>(unpack(std::move(child)), HEAVY);
255}
256
257/// @brief Draw a double border around the element.
258/// @ingroup dom
259/// @see border
260/// @see borderLight
261/// @see borderDouble
262/// @see borderHeavy
263/// @see borderRounded
264/// @see borderEmpty
265/// @see borderStyled
266/// @see borderWith
267///
268/// Add a border around an element
269///
270/// ### Example
271///
272/// ```cpp
273/// // Use 'borderDouble' as a function...
274/// Element document = borderDouble(text("The element"));
275///
276/// // ...Or as a 'pipe'.
277/// Element document = text("The element") | borderDouble;
278/// ```
279///
280/// ### Output
281///
282/// ```bash
283/// ╔══════════════╗
284/// ║The element ║
285/// ╚══════════════╝
286/// ```
288 return std::make_shared<Border>(unpack(std::move(child)), DOUBLE);
289}
290
291/// @brief Draw a rounded border around the element.
292/// @ingroup dom
293/// @see border
294/// @see borderLight
295/// @see borderDouble
296/// @see borderHeavy
297/// @see borderRounded
298/// @see borderEmpty
299/// @see borderStyled
300/// @see borderWith
301///
302/// Add a border around an element
303///
304/// ### Example
305///
306/// ```cpp
307/// // Use 'borderRounded' as a function...
308/// Element document = borderRounded(text("The element"));
309///
310/// // ...Or as a 'pipe'.
311/// Element document = text("The element") | borderRounded;
312/// ```
313///
314/// ### Output
315///
316/// ```bash
317/// ╭──────────────╮
318/// │The element │
319/// ╰──────────────╯
320/// ```
322 return std::make_shared<Border>(unpack(std::move(child)), ROUNDED);
323}
324
325/// @brief Draw an empty border around the element.
326/// @ingroup dom
327/// @see border
328/// @see borderLight
329/// @see borderDouble
330/// @see borderHeavy
331/// @see borderRounded
332/// @see borderEmpty
333/// @see borderStyled
334/// @see borderWith
335///
336/// Add a border around an element
337///
338/// ### Example
339///
340/// ```cpp
341/// // Use 'borderRounded' as a function...
342/// Element document = borderRounded(text("The element"));
343///
344/// // ...Or as a 'pipe'.
345/// Element document = text("The element") | borderRounded;
346/// ```
347///
348/// ### Output
349///
350/// ```bash
351///
352/// The element
353///
354/// ```
356 return std::make_shared<Border>(unpack(std::move(child)), EMPTY);
357}
358
359/// @brief Draw window with a title and a border around the element.
360/// @param title The title of the window.
361/// @param content The element to be wrapped.
362/// @ingroup dom
363/// @see border
364///
365/// ### Example
366///
367/// ```cpp
368/// Element document = window(text("Title"),
369/// text("content")
370/// );
371/// ```
372///
373/// ### Output
374///
375/// ```bash
376/// ┌Title──┐
377/// │content│
378/// └───────┘
379/// ```
380Element window(Element title, Element content) {
381 return std::make_shared<Border>(unpack(std::move(content), std::move(title)),
382 ROUNDED);
383}
384} // namespace ftxui
385
386// Copyright 2020 Arthur Sonzogni. All rights reserved.
387// Use of this source code is governed by the MIT license that can be found in
388// the LICENSE file.
Elements children_
Definition node.hpp:48
virtual void SetBox(Box box)
Assign a position and a dimension to an element for drawing.
Definition node.cpp:21
Requirement requirement_
Definition node.hpp:49
virtual void ComputeRequirement()
Compute how much space an elements needs.
Definition node.cpp:14
Box box_
Definition node.hpp:50
Element borderDouble(Element)
Draw a double border around the element.
Definition border.cpp:287
std::function< Element(Element)> Decorator
Definition elements.hpp:20
std::shared_ptr< Node > Element
Definition elements.hpp:18
Decorator borderWith(Pixel)
Same as border but with a constant Pixel around the element.
Definition border.cpp:174
Element borderRounded(Element)
Draw a rounded border around the element.
Definition border.cpp:321
Element window(Element title, Element content)
Draw window with a title and a border around the element.
Definition border.cpp:380
std::vector< Element > Elements
Definition elements.hpp:19
Element borderHeavy(Element)
Draw a heavy border around the element.
Definition border.cpp:253
Element borderLight(Element)
Draw a light border around the element.
Definition border.cpp:219
Decorator borderStyled(BorderStyle)
Same as border but with different styles.
Definition border.cpp:183
Element border(Element)
Draw a border around the element.
Definition border.cpp:167
Element borderEmpty(Element)
Draw an empty border around the element.
Definition border.cpp:355
BorderStyle
Definition elements.hpp:23
@ EMPTY
Definition elements.hpp:23
@ DOUBLE
Definition elements.hpp:23
@ HEAVY
Definition elements.hpp:23
@ ROUNDED
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