FTXUI  0.11.1
C++ functional terminal UI.
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 
14 namespace ftxui {
15 
16 static 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 
29 class 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();
44  requirement_.min_x += 2;
45  requirement_.min_y += 2;
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  for (float x = box_.x_min + 1; x < box_.x_max; ++x) {
93  screen.at(x, box_.y_min) = charset[4];
94  screen.at(x, box_.y_max) = charset[4];
95  }
96  for (float y = box_.y_min + 1; y < box_.y_max; ++y) {
97  screen.at(box_.x_min, y) = charset[5];
98  screen.at(box_.x_max, y) = charset[5];
99  }
100 
101  // Draw title.
102  if (children_.size() == 2)
103  children_[1]->Render(screen);
104  }
105 
106  void RenderChar(Screen& screen) {
107  screen.PixelAt(box_.x_min, box_.y_min) = charset_pixel[0];
108  screen.PixelAt(box_.x_max, box_.y_min) = charset_pixel[1];
109  screen.PixelAt(box_.x_min, box_.y_max) = charset_pixel[2];
110  screen.PixelAt(box_.x_max, box_.y_max) = charset_pixel[3];
111  for (float x = box_.x_min + 1; x < box_.x_max; ++x) {
112  screen.PixelAt(x, box_.y_min) = charset_pixel[4];
113  screen.PixelAt(x, box_.y_max) = charset_pixel[4];
114  }
115  for (float y = box_.y_min + 1; y < box_.y_max; ++y) {
116  screen.PixelAt(box_.x_min, y) = charset_pixel[5];
117  screen.PixelAt(box_.x_max, y) = charset_pixel[5];
118  }
119  }
120 };
121 
122 /// @brief Draw a border around the element.
123 /// @ingroup dom
124 /// @see border
125 /// @see borderLight
126 /// @see borderDouble
127 /// @see borderHeavy
128 /// @see borderEmpty
129 /// @see borderRounded
130 ///
131 /// Add a border around an element
132 ///
133 /// ### Example
134 ///
135 /// ```cpp
136 /// // Use 'border' as a function...
137 /// Element document = border(text("The element"));
138 ///
139 /// // ...Or as a 'pipe'.
140 /// Element document = text("The element") | border;
141 /// ```
142 ///
143 /// ### Output
144 ///
145 /// ```bash
146 /// ┌───────────┐
147 /// │The element│
148 /// └───────────┘
149 /// ```
151  return std::make_shared<Border>(unpack(std::move(child)), ROUNDED);
152 }
153 
154 /// @brief Same as border but with a constant Pixel around the element.
155 /// @ingroup dom
156 /// @see border
158  return [pixel](Element child) {
159  return std::make_shared<Border>(unpack(std::move(child)), pixel);
160  };
161 }
162 
163 /// @brief Same as border but with different styles.
164 /// @ingroup dom
165 /// @see border
167  return [style](Element child) {
168  return std::make_shared<Border>(unpack(std::move(child)), style);
169  };
170 }
171 
172 /// @brief Draw a light border around the element.
173 /// @ingroup dom
174 /// @see border
175 /// @see borderLight
176 /// @see borderDouble
177 /// @see borderHeavy
178 /// @see borderRounded
179 /// @see borderEmpty
180 /// @see borderStyled
181 /// @see borderWith
182 ///
183 /// Add a border around an element
184 ///
185 /// ### Example
186 ///
187 /// ```cpp
188 /// // Use 'borderLight' as a function...
189 /// Element document = borderLight(text("The element"));
190 ///
191 /// // ...Or as a 'pipe'.
192 /// Element document = text("The element") | borderLight;
193 /// ```
194 ///
195 /// ### Output
196 ///
197 /// ```bash
198 /// ┌──────────────┐
199 /// │The element │
200 /// └──────────────┘
201 /// ```
203  return std::make_shared<Border>(unpack(std::move(child)), LIGHT);
204 }
205 
206 /// @brief Draw a heavy border around the element.
207 /// @ingroup dom
208 /// @see border
209 /// @see borderLight
210 /// @see borderDouble
211 /// @see borderHeavy
212 /// @see borderRounded
213 /// @see borderEmpty
214 /// @see borderStyled
215 /// @see borderWith
216 ///
217 /// Add a border around an element
218 ///
219 /// ### Example
220 ///
221 /// ```cpp
222 /// // Use 'borderHeavy' as a function...
223 /// Element document = borderHeavy(text("The element"));
224 ///
225 /// // ...Or as a 'pipe'.
226 /// Element document = text("The element") | borderHeavy;
227 /// ```
228 ///
229 /// ### Output
230 ///
231 /// ```bash
232 /// ┏━━━━━━━━━━━━━━┓
233 /// ┃The element ┃
234 /// ┗━━━━━━━━━━━━━━┛
235 /// ```
237  return std::make_shared<Border>(unpack(std::move(child)), HEAVY);
238 }
239 
240 /// @brief Draw a double border around the element.
241 /// @ingroup dom
242 /// @see border
243 /// @see borderLight
244 /// @see borderDouble
245 /// @see borderHeavy
246 /// @see borderRounded
247 /// @see borderEmpty
248 /// @see borderStyled
249 /// @see borderWith
250 ///
251 /// Add a border around an element
252 ///
253 /// ### Example
254 ///
255 /// ```cpp
256 /// // Use 'borderDouble' as a function...
257 /// Element document = borderDouble(text("The element"));
258 ///
259 /// // ...Or as a 'pipe'.
260 /// Element document = text("The element") | borderDouble;
261 /// ```
262 ///
263 /// ### Output
264 ///
265 /// ```bash
266 /// ╔══════════════╗
267 /// ║The element ║
268 /// ╚══════════════╝
269 /// ```
271  return std::make_shared<Border>(unpack(std::move(child)), DOUBLE);
272 }
273 
274 /// @brief Draw a rounded border around the element.
275 /// @ingroup dom
276 /// @see border
277 /// @see borderLight
278 /// @see borderDouble
279 /// @see borderHeavy
280 /// @see borderRounded
281 /// @see borderEmpty
282 /// @see borderStyled
283 /// @see borderWith
284 ///
285 /// Add a border around an element
286 ///
287 /// ### Example
288 ///
289 /// ```cpp
290 /// // Use 'borderRounded' as a function...
291 /// Element document = borderRounded(text("The element"));
292 ///
293 /// // ...Or as a 'pipe'.
294 /// Element document = text("The element") | borderRounded;
295 /// ```
296 ///
297 /// ### Output
298 ///
299 /// ```bash
300 /// ╭──────────────╮
301 /// │The element │
302 /// ╰──────────────╯
303 /// ```
305  return std::make_shared<Border>(unpack(std::move(child)), ROUNDED);
306 }
307 
308 /// @brief Draw an empty border around the element.
309 /// @ingroup dom
310 /// @see border
311 /// @see borderLight
312 /// @see borderDouble
313 /// @see borderHeavy
314 /// @see borderRounded
315 /// @see borderEmpty
316 /// @see borderStyled
317 /// @see borderWith
318 ///
319 /// Add a border around an element
320 ///
321 /// ### Example
322 ///
323 /// ```cpp
324 /// // Use 'borderRounded' as a function...
325 /// Element document = borderRounded(text("The element"));
326 ///
327 /// // ...Or as a 'pipe'.
328 /// Element document = text("The element") | borderRounded;
329 /// ```
330 ///
331 /// ### Output
332 ///
333 /// ```bash
334 ///
335 /// The element
336 ///
337 /// ```
339  return std::make_shared<Border>(unpack(std::move(child)), EMPTY);
340 }
341 
342 /// @brief Draw window with a title and a border around the element.
343 /// @param title The title of the window.
344 /// @param content The element to be wrapped.
345 /// @ingroup dom
346 /// @see border
347 ///
348 /// ### Example
349 ///
350 /// ```cpp
351 /// Element document = window(text("Title"),
352 /// text("content")
353 /// );
354 /// ```
355 ///
356 /// ### Output
357 ///
358 /// ```bash
359 /// ┌Title──┐
360 /// │content│
361 /// └───────┘
362 /// ```
363 Element window(Element title, Element content) {
364  return std::make_shared<Border>(unpack(std::move(content), std::move(title)),
365  ROUNDED);
366 }
367 } // namespace ftxui
368 
369 // Copyright 2020 Arthur Sonzogni. All rights reserved.
370 // Use of this source code is governed by the MIT license that can be found in
371 // the LICENSE file.
Node()
Definition: node.cpp:8
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:270
std::function< Element(Element)> Decorator
Definition: elements.hpp:18
std::shared_ptr< Node > Element
Definition: elements.hpp:16
Decorator borderWith(Pixel)
Same as border but with a constant Pixel around the element.
Definition: border.cpp:157
Element borderRounded(Element)
Draw a rounded border around the element.
Definition: border.cpp:304
Element window(Element title, Element content)
Draw window with a title and a border around the element.
Definition: border.cpp:363
Element borderHeavy(Element)
Draw a heavy border around the element.
Definition: border.cpp:236
std::vector< Element > Elements
Definition: elements.hpp:17
Element borderLight(Element)
Draw a light border around the element.
Definition: border.cpp:202
Decorator borderStyled(BorderStyle)
Same as border but with different styles.
Definition: border.cpp:166
void Render(Screen &screen, const Element &node)
Display an element on a ftxui::Screen.
Definition: node.cpp:40
Element border(Element)
Draw a border around the element.
Definition: border.cpp:150
Element borderEmpty(Element)
Draw an empty border around the element.
Definition: border.cpp:338
BorderStyle
Definition: elements.hpp:21
@ EMPTY
Definition: elements.hpp:21
@ DOUBLE
Definition: elements.hpp:21
@ HEAVY
Definition: elements.hpp:21
@ ROUNDED
Definition: elements.hpp:21
@ LIGHT
Definition: elements.hpp:21
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