22 using Charset = std::array<std::string, 6>;
23 using Charsets = std::array<Charset, 6>;
25 static Charsets simple_border_charset = {
26 Charset{
"┌",
"┐",
"└",
"┘",
"─",
"│"},
27 Charset{
"┏",
"┓",
"┗",
"┛",
"╍",
"╏"},
28 Charset{
"┏",
"┓",
"┗",
"┛",
"━",
"┃"},
29 Charset{
"╔",
"╗",
"╚",
"╝",
"═",
"║"},
30 Charset{
"╭",
"╮",
"╰",
"╯",
"─",
"│"},
31 Charset{
" ",
" ",
" ",
" ",
" ",
" "},
35 class Border :
public Node {
39 std::optional<Color> foreground_color = std::nullopt)
40 : Node(std::move(children)),
41 charset_(simple_border_charset[style])
43 foreground_color_(foreground_color) {}
45 const Charset& charset_;
46 std::optional<Color> foreground_color_;
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_.selected_box.x_min++;
58 requirement_.selected_box.x_max++;
59 requirement_.selected_box.y_min++;
60 requirement_.selected_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 = box.x_max - 1;
69 title_box.y_min = box.y_min;
70 title_box.y_max = box.y_min;
71 children_[1]->SetBox(title_box);
77 children_[0]->SetBox(box);
80 void Render(Screen& screen)
override {
82 children_[0]->Render(screen);
85 if (box_.x_min >= box_.x_max || box_.y_min >= box_.y_max) {
89 screen.at(box_.x_min, box_.y_min) = charset_[0];
90 screen.at(box_.x_max, box_.y_min) = charset_[1];
91 screen.at(box_.x_min, box_.y_max) = charset_[2];
92 screen.at(box_.x_max, box_.y_max) = charset_[3];
94 for (
int x = box_.x_min + 1; x < box_.x_max; ++x) {
95 Pixel& p1 = screen.PixelAt(x, box_.y_min);
96 Pixel& p2 = screen.PixelAt(x, box_.y_max);
97 p1.character = charset_[4];
98 p2.character = charset_[4];
102 for (
int y = box_.y_min + 1; y < box_.y_max; ++y) {
103 Pixel& p3 = screen.PixelAt(box_.x_min, y);
104 Pixel& p4 = screen.PixelAt(box_.x_max, y);
105 p3.character = charset_[5];
106 p4.character = charset_[5];
112 if (children_.size() == 2) {
113 children_[1]->Render(screen);
117 if (foreground_color_) {
118 for (
int x = box_.x_min; x <= box_.x_max; ++x) {
119 screen.PixelAt(x, box_.y_min).foreground_color = *foreground_color_;
120 screen.PixelAt(x, box_.y_max).foreground_color = *foreground_color_;
122 for (
int y = box_.y_min; y <= box_.y_max; ++y) {
123 screen.PixelAt(box_.x_min, y).foreground_color = *foreground_color_;
124 screen.PixelAt(box_.x_max, y).foreground_color = *foreground_color_;
131 class BorderPixel :
public Node {
133 BorderPixel(
Elements children, Pixel pixel)
134 : Node(std::move(children)), pixel_(std::move(pixel)) {}
139 void ComputeRequirement()
override {
141 requirement_ = children_[0]->requirement();
142 requirement_.min_x += 2;
143 requirement_.min_y += 2;
144 if (children_.size() == 2) {
146 std::max(requirement_.min_x, children_[1]->requirement().min_x + 2);
148 requirement_.selected_box.x_min++;
149 requirement_.selected_box.x_max++;
150 requirement_.selected_box.y_min++;
151 requirement_.selected_box.y_max++;
154 void SetBox(Box box)
override {
156 if (children_.size() == 2) {
158 title_box.x_min = box.x_min + 1;
159 title_box.x_max = box.x_max - 1;
160 title_box.y_min = box.y_min;
161 title_box.y_max = box.y_min;
162 children_[1]->SetBox(title_box);
168 children_[0]->SetBox(box);
171 void Render(Screen& screen)
override {
173 children_[0]->Render(screen);
176 if (box_.x_min >= box_.x_max || box_.y_min >= box_.y_max) {
180 screen.PixelAt(box_.x_min, box_.y_min) = pixel_;
181 screen.PixelAt(box_.x_max, box_.y_min) = pixel_;
182 screen.PixelAt(box_.x_min, box_.y_max) = pixel_;
183 screen.PixelAt(box_.x_max, box_.y_max) = pixel_;
185 for (
int x = box_.x_min + 1; x < box_.x_max; ++x) {
186 screen.PixelAt(x, box_.y_min) = pixel_;
187 screen.PixelAt(x, box_.y_max) = pixel_;
189 for (
int y = box_.y_min + 1; y < box_.y_max; ++y) {
190 screen.PixelAt(box_.x_min, y) = pixel_;
191 screen.PixelAt(box_.x_max, y) = pixel_;
229 return std::make_shared<Border>(unpack(std::move(child)),
ROUNDED);
236 return [pixel](
Element child) {
237 return std::make_shared<BorderPixel>(unpack(std::move(child)), pixel);
245 return [style](
Element child) {
246 return std::make_shared<Border>(unpack(std::move(child)), style);
254 return [foreground_color](
Element child) {
255 return std::make_shared<Border>(unpack(std::move(child)),
ROUNDED,
264 return [style, foreground_color](
Element child) {
265 return std::make_shared<Border>(unpack(std::move(child)), style,
302 return std::make_shared<Border>(unpack(std::move(child)),
DASHED);
337 return std::make_shared<Border>(unpack(std::move(child)),
LIGHT);
372 return std::make_shared<Border>(unpack(std::move(child)),
HEAVY);
407 return std::make_shared<Border>(unpack(std::move(child)),
DOUBLE);
442 return std::make_shared<Border>(unpack(std::move(child)),
ROUNDED);
477 return std::make_shared<Border>(unpack(std::move(child)),
EMPTY);
509 return std::make_shared<Border>(unpack(std::move(content), std::move(title)),
A class representing terminal colors.
virtual void SetBox(Box box)
Assign a position and a dimension to an element for drawing.
virtual void ComputeRequirement()
Compute how much space an elements 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.
std::function< Element(Element)> Decorator
Element borderDashed(Element)
Draw a dashed border around the element.
std::shared_ptr< Node > Element
Element borderRounded(Element)
Draw a rounded border around the element.
Element borderHeavy(Element)
Draw a heavy border around the element.
std::vector< Element > Elements
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.
A Unicode character and its associated style.