FTXUI  3.0.0
C++ functional terminal UI.
Loading...
Searching...
No Matches
gridbox.cpp
Go to the documentation of this file.
1#include <algorithm> // for max, min
2#include <cstddef> // for size_t
3#include <memory> // for __shared_ptr_access, shared_ptr, make_shared, allocator_traits<>::value_type
4#include <utility> // for move
5#include <vector> // for vector, __alloc_traits<>::value_type
6
7#include "ftxui/dom/box_helper.hpp" // for Element, Compute
8#include "ftxui/dom/elements.hpp" // for Elements, filler, Element, gridbox
9#include "ftxui/dom/node.hpp" // for Node
10#include "ftxui/dom/requirement.hpp" // for Requirement
11#include "ftxui/screen/box.hpp" // for Box
12
13namespace ftxui {
14class Screen;
15
16class GridBox : public Node {
17 public:
18 explicit GridBox(std::vector<Elements> lines) : lines_(std::move(lines)) {
19 y_size = (int)lines_.size();
20 for (const auto& line : lines_) {
21 x_size = std::max(x_size, (int)line.size());
22 }
23 for (auto& line : lines_) {
24 while (line.size() < (size_t)x_size) {
25 line.push_back(filler());
26 }
27 }
28 }
29
30 void ComputeRequirement() override {
37
38 for (auto& line : lines_) {
39 for (auto& cell : line) {
40 cell->ComputeRequirement();
41
42 // Determine focus based on the focused child.
43 if (requirement_.selection >= cell->requirement().selection) {
44 continue;
45 }
46 requirement_.selection = cell->requirement().selection;
47 requirement_.selected_box = cell->requirement().selected_box;
50 }
51 }
52
53 // Work on the x-axis.
54 for (int x = 0; x < x_size; ++x) {
55 int min_x = 0;
56 for (int y = 0; y < y_size; ++y) {
57 min_x = std::max(min_x, lines_[y][x]->requirement().min_x);
58 }
59 requirement_.min_x += min_x;
60 }
61
62 // Work on the y-axis.
63 for (int y = 0; y < y_size; ++y) {
64 int min_y = 0;
65 for (int x = 0; x < x_size; ++x) {
66 min_y = std::max(min_y, lines_[y][x]->requirement().min_y);
67 }
68 requirement_.min_y += min_y;
69 }
70 }
71
72 void SetBox(Box box) override {
73 Node::SetBox(box);
74
75 box_helper::Element init;
76 init.min_size = 0;
77 init.flex_grow = 1024; // NOLINT
78 init.flex_shrink = 1024; // NOLINT
79 std::vector<box_helper::Element> elements_x(x_size, init);
80 std::vector<box_helper::Element> elements_y(y_size, init);
81
82 for (int y = 0; y < y_size; ++y) {
83 for (int x = 0; x < x_size; ++x) {
84 const auto& cell = lines_[y][x];
85 const auto& requirement = cell->requirement();
86 auto& e_x = elements_x[x];
87 auto& e_y = elements_y[y];
88 e_x.min_size = std::max(e_x.min_size, requirement.min_x);
89 e_y.min_size = std::max(e_y.min_size, requirement.min_y);
90 e_x.flex_grow = std::min(e_x.flex_grow, requirement.flex_grow_x);
91 e_y.flex_grow = std::min(e_y.flex_grow, requirement.flex_grow_y);
92 e_x.flex_shrink = std::min(e_x.flex_shrink, requirement.flex_shrink_x);
93 e_y.flex_shrink = std::min(e_y.flex_shrink, requirement.flex_shrink_y);
94 }
95 }
96
97 int target_size_x = box.x_max - box.x_min + 1;
98 int target_size_y = box.y_max - box.y_min + 1;
99 box_helper::Compute(&elements_x, target_size_x);
100 box_helper::Compute(&elements_y, target_size_y);
101
102 Box box_y = box;
103 int y = box_y.y_min;
104 for (int iy = 0; iy < y_size; ++iy) {
105 box_y.y_min = y;
106 y += elements_y[iy].size;
107 box_y.y_max = y - 1;
108
109 Box box_x = box_y;
110 int x = box_x.x_min;
111 for (int ix = 0; ix < x_size; ++ix) {
112 box_x.x_min = x;
113 x += elements_x[ix].size;
114 box_x.x_max = x - 1;
115 lines_[iy][ix]->SetBox(box_x);
116 }
117 }
118 }
119
120 void Render(Screen& screen) override {
121 for (auto& line : lines_) {
122 for (auto& cell : line) {
123 cell->Render(screen);
124 }
125 }
126 }
127
128 int x_size = 0;
129 int y_size = 0;
130 std::vector<Elements> lines_;
131};
132
133/// @brief A container displaying a grid of elements.
134/// @param lines A list of lines, each line being a list of elements.
135/// @return The container.
136///
137/// #### Example
138///
139/// ```cpp
140/// auto cell = [](const char* t) { return text(t) | border; };
141/// auto document = gridbox({
142/// {cell("north-west") , cell("north") , cell("north-east")} ,
143/// {cell("west") , cell("center") , cell("east")} ,
144/// {cell("south-west") , cell("south") , cell("south-east")} ,
145/// });
146/// ```
147/// Output:
148/// ```
149///╭──────────╮╭──────╮╭──────────╮
150///│north-west││north ││north-east│
151///╰──────────╯╰──────╯╰──────────╯
152///╭──────────╮╭──────╮╭──────────╮
153///│west ││center││east │
154///╰──────────╯╰──────╯╰──────────╯
155///╭──────────╮╭──────╮╭──────────╮
156///│south-west││south ││south-east│
157///╰──────────╯╰──────╯╰──────────╯
158/// ```
159Element gridbox(std::vector<Elements> lines) {
160 return std::make_shared<GridBox>(std::move(lines));
161}
162
163} // namespace ftxui
164
165// Copyright 2020 Arthur Sonzogni. All rights reserved.
166// Use of this source code is governed by the MIT license that can be found in
167// the LICENSE file.
virtual void SetBox(Box box)
Assign a position and a dimension to an element for drawing.
Definition node.cpp:22
Requirement requirement_
Definition node.hpp:54
Requirement requirement()
Definition node.hpp:34
void Compute(std::vector< Element > *elements, int target_size)
std::shared_ptr< Node > Element
Definition elements.hpp:18
Element gridbox(std::vector< Elements > lines)
A container displaying a grid of elements.
Definition gridbox.cpp:159
Element filler()
An element that will take expand proportionnally to the space left in a container.
Definition flex.cpp:95
int x_max
Definition box.hpp:8
int x_min
Definition box.hpp:7