FTXUI 6.1.9
C++ functional terminal UI.
载入中...
搜索中...
未找到
src/ftxui/dom/gridbox.cpp
浏览该文件的文档.
1// Copyright 2020 Arthur Sonzogni. All rights reserved.
2// 本源代码的使用受 MIT 许可的约束,该许可可在 LICENSE 文件中找到。
3#include <algorithm> // for max, min
4#include <cstddef> // for size_t
5#include <memory> // for __shared_ptr_access, shared_ptr, make_shared, allocator_traits<>::value_type
6#include <utility> // for move
7#include <vector> // for vector, __alloc_traits<>::value_type
8
9#include "ftxui/dom/box_helper.hpp" // for Element, Compute
10#include "ftxui/dom/elements.hpp" // for Elements, filler, Element, gridbox
11#include "ftxui/dom/node.hpp" // for Node
12#include "ftxui/dom/requirement.hpp" // for Requirement
13#include "ftxui/screen/box.hpp" // for Box
14
15namespace ftxui {
16class Screen;
17
18namespace {
19
20// 将列表 U[n] 的值累加到 v[n] 中。使得:
21// V[0] = 0;
22// V[n+1] = v[n] + U[n]
23// 返回 U[n] 的总和。
24int Integrate(std::vector<int>& elements) {
25 int accu = 0;
26 for (auto& i : elements) {
27 const int old_accu = accu;
28 accu += i;
29 i = old_accu;
30 }
31 return accu;
32}
33
34class GridBox : public Node {
35 public:
36 explicit GridBox(std::vector<Elements> lines) : lines_(std::move(lines)) {
37 y_size = static_cast<int>(lines_.size());
38 for (const auto& line : lines_) {
39 x_size = std::max(x_size, int(line.size()));
40 }
41
42 // Fill in empty cells, in case the user did not used the API correctly:
43 for (auto& line : lines_) {
44 while (line.size() < size_t(x_size)) {
45 line.push_back(filler());
46 }
47 }
48 }
49
50 void ComputeRequirement() override {
51 requirement_ = Requirement{};
52 for (auto& line : lines_) {
53 for (auto& cell : line) {
54 cell->ComputeRequirement();
55 }
56 }
57
58 // Compute the size of each columns/row.
59 std::vector<int> size_x(x_size, 0);
60 std::vector<int> size_y(y_size, 0);
61 for (int x = 0; x < x_size; ++x) {
62 for (int y = 0; y < y_size; ++y) {
63 size_x[x] = std::max(size_x[x], lines_[y][x]->requirement().min_x);
64 size_y[y] = std::max(size_y[y], lines_[y][x]->requirement().min_y);
65 }
66 }
67
68 requirement_.min_x = Integrate(size_x);
69 requirement_.min_y = Integrate(size_y);
70
71 // Forward the focused/focused child state:
72 for (int x = 0; x < x_size; ++x) {
73 for (int y = 0; y < y_size; ++y) {
74 if (requirement_.focused.enabled ||
75 !lines_[y][x]->requirement().focused.enabled) {
76 continue;
77 }
78 requirement_.focused = lines_[y][x]->requirement().focused;
79 requirement_.focused.box.Shift(size_x[x], size_y[y]);
80 }
81 }
82 }
83
84 void SetBox(Box box) override {
85 Node::SetBox(box);
86
87 box_helper::Element init;
88 init.min_size = 0;
89 init.flex_grow = 1024; // NOLINT
90 init.flex_shrink = 1024; // NOLINT
91 std::vector<box_helper::Element> elements_x(x_size, init);
92 std::vector<box_helper::Element> elements_y(y_size, init);
93
94 for (int y = 0; y < y_size; ++y) {
95 for (int x = 0; x < x_size; ++x) {
96 const auto& cell = lines_[y][x];
97 const auto& requirement = cell->requirement();
98 auto& e_x = elements_x[x];
99 auto& e_y = elements_y[y];
100 e_x.min_size = std::max(e_x.min_size, requirement.min_x);
101 e_y.min_size = std::max(e_y.min_size, requirement.min_y);
102 e_x.flex_grow = std::min(e_x.flex_grow, requirement.flex_grow_x);
103 e_y.flex_grow = std::min(e_y.flex_grow, requirement.flex_grow_y);
104 e_x.flex_shrink = std::min(e_x.flex_shrink, requirement.flex_shrink_x);
105 e_y.flex_shrink = std::min(e_y.flex_shrink, requirement.flex_shrink_y);
106 }
107 }
108
109 const int target_size_x = box.x_max - box.x_min + 1;
110 const int target_size_y = box.y_max - box.y_min + 1;
111 box_helper::Compute(&elements_x, target_size_x);
112 box_helper::Compute(&elements_y, target_size_y);
113
114 Box box_y = box;
115 int y = box_y.y_min;
116 for (int iy = 0; iy < y_size; ++iy) {
117 box_y.y_min = y;
118 y += elements_y[iy].size;
119 box_y.y_max = y - 1;
120
121 Box box_x = box_y;
122 int x = box_x.x_min;
123 for (int ix = 0; ix < x_size; ++ix) {
124 box_x.x_min = x;
125 x += elements_x[ix].size;
126 box_x.x_max = x - 1;
127 lines_[iy][ix]->SetBox(box_x);
128 }
129 }
130 }
131
132 void Render(Screen& screen) override {
133 for (auto& line : lines_) {
134 for (auto& cell : line) {
135 cell->Render(screen);
136 }
137 }
138 }
139
140 int x_size = 0;
141 int y_size = 0;
142 std::vector<Elements> lines_;
143};
144} // namespace
145 //
146/// @brief 一个显示元素网格的容器。
147/// @param lines 行的列表,每行都是元素的列表。
148/// @return 容器。
149///
150/// #### 示例
151///
152/// ```cpp
153/// auto cell = [](const char* t) { return text(t) | border; };
154/// auto document = gridbox({
155/// {cell("north-west") , cell("north") , cell("north-east")} ,
156/// {cell("west") , cell("center") , cell("east")} ,
157/// {cell("south-west") , cell("south") , cell("south-east")} ,
158/// });
159/// ```
160/// Output:
161/// ```
162/// ╭──────────╮╭──────╮╭──────────╮
163/// │north-west││north ││north-east│
164/// ╰──────────╯╰──────╯╰──────────╯
165/// ╭──────────╮╭──────╮╭──────────╮
166/// │west ││center││east │
167/// ╰──────────╯╰──────╯╰──────────╯
168/// ╭──────────╮╭──────╮╭──────────╮
169/// │south-west││south ││south-east│
170/// ╰──────────╯╰──────╯╰──────────╯
171/// ```
172Element gridbox(std::vector<Elements> lines) {
173 return std::make_shared<GridBox>(std::move(lines));
174}
175
176} // namespace ftxui
#include "ftxui/component/component_base.hpp" // 用于 ComponentBase
std::shared_ptr< Node > Element
Element gridbox(std::vector< Elements > lines)
一个显示元素网格的容器。
std::vector< Elements > lines_