22using Charset = std::array<std::string, 6>;
23using Charsets = std::array<Charset, 6>;
25static Charsets simple_border_charset = {
26 Charset{
"┌",
"┐",
"└",
"┘",
"─",
"│"},
27 Charset{
"┏",
"┓",
"┗",
"┛",
"╍",
"╏"},
28 Charset{
"┏",
"┓",
"┗",
"┛",
"━",
"┃"},
29 Charset{
"╔",
"╗",
"╚",
"╝",
"═",
"║"},
30 Charset{
"╭",
"╮",
"╰",
"╯",
"─",
"│"},
31 Charset{
" ",
" ",
" ",
" ",
" ",
" "},
35class Border :
public Node {
39 std::optional<Color> foreground_color = std::nullopt)
40 : Node(std::move(children)),
41 charset_(simple_border_charset[style])
48 void ComputeRequirement()
override {
50 requirement_ = children_[0]->requirement();
51 requirement_.min_x += 2;
52 requirement_.min_y += 2;
53 if (children_.size() == 2) {
55 std::max(requirement_.min_x, children_[1]->requirement().min_x + 2);
57 requirement_.focused.box.x_min++;
58 requirement_.focused.box.x_max++;
59 requirement_.focused.box.y_min++;
60 requirement_.focused.box.y_max++;
63 void SetBox(Box box)
override {
65 if (children_.size() == 2) {
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);
78 children_[0]->SetBox(box);
81 void Render(Screen& screen)
override {
83 children_[0]->Render(screen);
86 if (box_.x_min >= box_.x_max || box_.y_min >= box_.y_max) {
90 screen.at(box_.x_min, box_.y_min) =
charset_[0];
91 screen.at(box_.x_max, box_.y_min) =
charset_[1];
92 screen.at(box_.x_min, box_.y_max) =
charset_[2];
93 screen.at(box_.x_max, box_.y_max) =
charset_[3];
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);
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);
113 if (children_.size() == 2) {
114 children_[1]->Render(screen);
118 if (foreground_color_) {
119 for (
int x = box_.x_min; x <= box_.x_max; ++x) {
123 for (
int y = box_.y_min; y <= box_.y_max; ++y) {
132class BorderPixel :
public Node {
134 BorderPixel(
Elements children, Pixel pixel)
135 : Node(std::move(children)), pixel_(std::move(pixel)) {}
140 void ComputeRequirement()
override {
142 requirement_ = children_[0]->requirement();
143 requirement_.min_x += 2;
144 requirement_.min_y += 2;
145 if (children_.size() == 2) {
147 std::max(requirement_.min_x, children_[1]->requirement().min_x + 2);
150 requirement_.focused.box.Shift(1, 1);
153 void SetBox(Box box)
override {
155 if (children_.size() == 2) {
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);
167 children_[0]->SetBox(box);
170 void Render(Screen& screen)
override {
172 children_[0]->Render(screen);
175 if (box_.x_min >= box_.x_max || box_.y_min >= box_.y_max) {
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_;
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_;
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_;
228 return std::make_shared<Border>(unpack(std::move(child)),
ROUNDED);
235 return [pixel](
Element child) {
236 return std::make_shared<BorderPixel>(unpack(std::move(child)), pixel);
244 return [style](
Element child) {
245 return std::make_shared<Border>(unpack(std::move(child)), style);
253 return [foreground_color](
Element child) {
254 return std::make_shared<Border>(unpack(std::move(child)),
ROUNDED,
263 return [style, foreground_color](
Element child) {
264 return std::make_shared<Border>(unpack(std::move(child)), style,
301 return std::make_shared<Border>(unpack(std::move(child)),
DASHED);
336 return std::make_shared<Border>(unpack(std::move(child)),
LIGHT);
371 return std::make_shared<Border>(unpack(std::move(child)),
HEAVY);
406 return std::make_shared<Border>(unpack(std::move(child)),
DOUBLE);
441 return std::make_shared<Border>(unpack(std::move(child)),
ROUNDED);
476 return std::make_shared<Border>(unpack(std::move(child)),
EMPTY);
508 return std::make_shared<Border>(unpack(std::move(content), std::move(title)),
virtual void SetBox(Box box)
Assign a position and a dimension to an element for drawing.
virtual void ComputeRequirement()
Compute how much space an element needs.
Element window(Element title, Element content, BorderStyle border=ROUNDED)
Draw window with a title and a border around the element.
Element borderDouble(Element)
Draw a double border around the element.
Element borderDashed(Element)
Draw a dashed border around the element.
Element borderRounded(Element)
Draw a rounded border around the element.
Element borderHeavy(Element)
Draw a heavy border around the element.
Element borderLight(Element)
Draw a light border around the element.
Decorator borderWith(const Pixel &)
Same as border but with a constant Pixel around the element.
Decorator borderStyled(BorderStyle)
Same as border but with different styles.
void Render(Screen &screen, const Element &element)
Display an element on a ftxui::Screen.
Element border(Element)
Draw a border around the element.
Element borderEmpty(Element)
Draw an empty border around the element.
BorderStyle
BorderStyle is an enumeration that represents the different styles of borders that can be applied to ...
Color is a class that represents a color in the terminal user interface.
A Unicode character and its associated style.
The FTXUI ftxui:: namespace.
std::function< Element(Element)> Decorator
std::shared_ptr< Node > Element
std::vector< Element > Elements
std::optional< Color > foreground_color_