23using Charset = std::array<std::string, 6>;
24using Charsets = std::array<Charset, 6>;
26static Charsets simple_border_charset = {
27 Charset{
"┌",
"┐",
"└",
"┘",
"─",
"│"},
28 Charset{
"┏",
"┓",
"┗",
"┛",
"╍",
"╏"},
29 Charset{
"┏",
"┓",
"┗",
"┛",
"━",
"┃"},
30 Charset{
"╔",
"╗",
"╚",
"╝",
"═",
"║"},
31 Charset{
"╭",
"╮",
"╰",
"╯",
"─",
"│"},
32 Charset{
" ",
" ",
" ",
" ",
" ",
" "},
36class Border :
public Node {
40 std::optional<Color> foreground_color = std::nullopt)
41 : Node(std::move(children)),
42 charset_(simple_border_charset[style])
49 void ComputeRequirement()
override {
50 Node::ComputeRequirement();
51 requirement_ = children_[0]->requirement();
52 requirement_.min_x += 2;
53 requirement_.min_y += 2;
54 if (children_.size() == 2) {
56 std::max(requirement_.min_x, children_[1]->requirement().min_x + 2);
58 requirement_.focused.box.x_min++;
59 requirement_.focused.box.x_max++;
60 requirement_.focused.box.y_min++;
61 requirement_.focused.box.y_max++;
64 void SetBox(Box box)
override {
66 if (children_.size() == 2) {
68 title_box.x_min = box.x_min + 1;
69 title_box.x_max = box.x_max - 1;
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 Cell& p1 = screen.CellAt(x, box_.y_min);
97 Cell& p2 = screen.CellAt(x, box_.y_max);
103 for (
int y = box_.y_min + 1;
y < box_.y_max; ++
y) {
104 Cell& p3 = screen.CellAt(box_.x_min,
y);
105 Cell& p4 = screen.CellAt(box_.x_max,
y);
113 if (children_.size() == 2) {
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) {
133 void RenderTitle(Screen& screen) {
134 std::vector<Cell> top_border;
135 for (
int x = box_.x_min + 1; x < box_.x_max; ++x) {
136 top_border.push_back(screen.CellAt(x, box_.y_min));
138 children_[1]->Render(screen);
139 for (
int x = box_.x_min + 1; x < box_.x_max; ++x) {
140 Cell& cell = screen.CellAt(x, box_.y_min);
141 const Cell& saved = top_border[x - box_.x_min - 1];
142 if (cell.character == saved.character) {
150class BorderCell :
public Node {
152 BorderCell(
Elements children, Cell pixel)
153 : Node(std::move(children)), pixel_(std::move(pixel)) {}
158 void ComputeRequirement()
override {
159 Node::ComputeRequirement();
160 requirement_ = children_[0]->requirement();
161 requirement_.min_x += 2;
162 requirement_.min_y += 2;
163 if (children_.size() == 2) {
165 std::max(requirement_.min_x, children_[1]->requirement().min_x + 2);
168 requirement_.focused.box.Shift(1, 1);
171 void SetBox(Box box)
override {
173 if (children_.size() == 2) {
175 title_box.x_min = box.x_min + 1;
176 title_box.x_max = box.x_max - 1;
177 title_box.y_min = box.y_min;
178 title_box.y_max = box.y_min;
179 children_[1]->SetBox(title_box);
185 children_[0]->SetBox(box);
188 void Render(Screen& screen)
override {
190 children_[0]->Render(screen);
193 if (box_.x_min >= box_.x_max || box_.y_min >= box_.y_max) {
197 screen.CellAt(box_.x_min, box_.y_min) = pixel_;
198 screen.CellAt(box_.x_max, box_.y_min) = pixel_;
199 screen.CellAt(box_.x_min, box_.y_max) = pixel_;
200 screen.CellAt(box_.x_max, box_.y_max) = pixel_;
202 for (
int x = box_.x_min + 1; x < box_.x_max; ++x) {
203 screen.CellAt(x, box_.y_min) = pixel_;
204 screen.CellAt(x, box_.y_max) = pixel_;
206 for (
int y = box_.y_min + 1;
y < box_.y_max; ++
y) {
207 screen.CellAt(box_.x_min,
y) = pixel_;
208 screen.CellAt(box_.x_max,
y) = pixel_;
246 return std::make_shared<Border>(unpack(std::move(child)),
ROUNDED);
253 return [pixel](
Element child) {
254 return std::make_shared<BorderCell>(unpack(std::move(child)), pixel);
262 return [style](
Element child) {
263 return std::make_shared<Border>(unpack(std::move(child)), style);
271 return [foreground_color](
Element child) {
272 return std::make_shared<Border>(unpack(std::move(child)),
ROUNDED,
281 return [style, foreground_color](
Element child) {
282 return std::make_shared<Border>(unpack(std::move(child)), style,
319 return std::make_shared<Border>(unpack(std::move(child)),
DASHED);
354 return std::make_shared<Border>(unpack(std::move(child)),
LIGHT);
389 return std::make_shared<Border>(unpack(std::move(child)),
HEAVY);
424 return std::make_shared<Border>(unpack(std::move(child)),
DOUBLE);
459 return std::make_shared<Border>(unpack(std::move(child)),
ROUNDED);
494 return std::make_shared<Border>(unpack(std::move(child)),
EMPTY);
526 return std::make_shared<Border>(unpack(std::move(content), std::move(title)),
Element window(Element title, Element content, BorderStyle border=ROUNDED)
Draw window with a title and a border around the element.
Element borderDouble(Element child)
Draw a double border around the element.
Element borderDashed(Element child)
Draw a dashed border around the element.
Element borderRounded(Element child)
Draw a rounded border around the element.
BorderStyle
BorderStyle is an enumeration that represents the different styles of borders that can be applied to ...
Element borderHeavy(Element child)
Draw a heavy border around the element.
Decorator borderWith(const Cell &pixel)
Same as border but with a constant Cell around the element.
Element borderLight(Element child)
Draw a light border around the element.
Decorator borderStyled(BorderStyle style)
Same as border but with different styles.
Element border(Element child)
Draw a border around the element.
Element borderEmpty(Element child)
Draw an empty border around the element.
The FTXUI ftxui:: namespace.
std::shared_ptr< Node > Element
std::vector< Element > Elements
std::function< Element(Element)> Decorator
void Render(Screen &screen, Node *node, Selection &selection)
std::optional< Color > foreground_color_