FTXUI 6.1.9
C++ functional terminal UI.
Loading...
Searching...
No Matches
flexbox_helper.cpp
Go to the documentation of this file.
1// Copyright 2021 Arthur Sonzogni. Todos los derechos reservados.
2// El uso de este código fuente se rige por la licencia MIT que se puede encontrar en
3// el archivo LICENSE.
5
6#include <algorithm> // para max, min
7#include <cstddef> // para size_t
8#include <ftxui/dom/flexbox_config.hpp> // para FlexboxConfig, FlexboxConfig::Direction, FlexboxConfig::AlignContent, FlexboxConfig::JustifyContent, FlexboxConfig::Wrap, FlexboxConfig::Direction::RowInversed, FlexboxConfig::AlignItems, FlexboxConfig::Direction::Row, FlexboxConfig::Direction::Column, FlexboxConfig::Direction::ColumnInversed, FlexboxConfig::Wrap::WrapInversed, FlexboxConfig::AlignContent::Stretch, FlexboxConfig::JustifyContent::Stretch, FlexboxConfig::Wrap::Wrap, FlexboxConfig::AlignContent::Center, FlexboxConfig::AlignContent::FlexEnd, FlexboxConfig::AlignContent::FlexStart, FlexboxConfig::AlignContent::SpaceAround, FlexboxConfig::AlignContent::SpaceBetween, FlexboxConfig::AlignContent::SpaceEvenly, FlexboxConfig::AlignItems::Center, FlexboxConfig::AlignItems::FlexEnd, FlexboxConfig::AlignItems::FlexStart, FlexboxConfig::AlignItems::Stretch, FlexboxConfig::JustifyContent::Center, FlexboxConfig::JustifyContent::FlexEnd, FlexboxConfig::JustifyContent::FlexStart, FlexboxConfig::JustifyContent::SpaceAround, FlexboxConfig::JustifyContent::SpaceBetween, FlexboxConfig::JustifyContent::SpaceEvenly, FlexboxConfig::Wrap::NoWrap
9#include <utility> // para swap, move
10#include <vector>
11
12#include "ftxui/dom/box_helper.hpp" // para Element, Compute
13
15
16namespace {
17void SymmetryXY(FlexboxConfig& c) {
18 std::swap(c.gap_x, c.gap_y);
19 switch (c.direction) {
22 break;
25 break;
28 break;
31 break;
32 }
33}
34
35void SymmetryX(FlexboxConfig& c) {
36 switch (c.direction) {
39 break;
42 break;
43 default:
44 break;
45 }
46}
47
48void SymmetryY(FlexboxConfig& c) {
49 switch (c.wrap) {
51 break;
54 break;
57 break;
58 }
59}
60
61void SymmetryXY(Global& g) {
62 SymmetryXY(g.config);
63 std::swap(g.size_x, g.size_y);
64 for (auto& b : g.blocks) {
65 std::swap(b.min_size_x, b.min_size_y);
66 std::swap(b.flex_grow_x, b.flex_grow_y);
67 std::swap(b.flex_shrink_x, b.flex_shrink_y);
68 std::swap(b.x, b.y);
69 std::swap(b.dim_x, b.dim_y);
70 }
71 for (auto& l : g.lines) {
72 std::swap(l.x, l.y);
73 std::swap(l.dim_x, l.dim_y);
74 }
75}
76
77void SymmetryX(Global& g) {
78 SymmetryX(g.config);
79 for (auto& b : g.blocks) {
80 b.x = g.size_x - b.x - b.dim_x;
81 }
82 for (auto& l : g.lines) {
83 l.x = g.size_x - l.x - l.dim_x;
84 }
85}
86
87void SymmetryY(Global& g) {
88 SymmetryY(g.config);
89 for (auto& b : g.blocks) {
90 b.y = g.size_y - b.y - b.dim_y;
91 }
92 for (auto& l : g.lines) {
93 l.y = g.size_y - l.y - l.dim_y;
94 }
95}
96
97void SetX(Global& global) {
98 for (auto& line : global.lines) {
99 std::vector<box_helper::Element> elements;
100 elements.reserve(line.blocks.size());
101 for (auto* block : line.blocks) {
102 box_helper::Element element;
103 element.min_size = block->min_size_x;
104 element.flex_grow =
105 block->flex_grow_x != 0 || global.config.justify_content ==
107 ? 1
108 : 0;
109 element.flex_shrink = block->flex_shrink_x;
110 elements.push_back(element);
111 }
112
114 &elements,
115 global.size_x - global.config.gap_x * (int(line.blocks.size()) - 1));
116
117 int x = 0;
118 for (size_t i = 0; i < line.blocks.size(); ++i) {
119 line.blocks[i]->x = x;
120 line.blocks[i]->dim_x = elements[i].size;
121 x += elements[i].size;
122 x += global.config.gap_x;
123 }
124 }
125
126 for (auto& line : global.lines) {
127 line.x = 0;
128 line.dim_x = global.size_x;
129 }
130}
131
132// NOLINTNEXTLINE(readability-function-cognitive-complexity)
133void SetY(Global& g) {
134 std::vector<box_helper::Element> elements;
135 elements.reserve(g.lines.size());
136 for (auto& line : g.lines) {
137 box_helper::Element element;
138 element.flex_shrink = line.blocks.front()->flex_shrink_y;
139 element.flex_grow = line.blocks.front()->flex_grow_y;
140 for (auto* block : line.blocks) {
141 element.min_size = std::max(element.min_size, block->min_size_y);
142 element.flex_shrink = std::min(element.flex_shrink, block->flex_shrink_y);
143 element.flex_grow = std::min(element.flex_grow, block->flex_grow_y);
144 }
145 elements.push_back(element);
146 }
147
148 // box_helper::Compute(&elements, g.size_y);
149 box_helper::Compute(&elements, 10000); // NOLINT
150
151 // [Alinear-contenido]
152 std::vector<int> ys(elements.size());
153 int y = 0;
154 for (size_t i = 0; i < elements.size(); ++i) {
155 ys[i] = y;
156 y += elements[i].size;
157 y += g.config.gap_y;
158 }
159 int remaining_space = std::max(0, g.size_y - y);
160 switch (g.config.align_content) {
162 break;
163 }
164
166 for (size_t i = 0; i < ys.size(); ++i) { // NOLINT
167 ys[i] += remaining_space;
168 }
169 break;
170 }
171
173 for (size_t i = 0; i < ys.size(); ++i) { // NOLINT
174 ys[i] += remaining_space / 2;
175 }
176 break;
177 }
178
180 for (int i = static_cast<int>(ys.size()) - 1; i >= 0; --i) { // NOLINT
181 const int shifted = remaining_space * (i + 0) / (i + 1);
182 ys[i] += shifted;
183 const int consumed = remaining_space - shifted;
184 elements[i].size += consumed;
185 remaining_space -= consumed;
186 }
187 break;
188 }
189
191 for (int i = static_cast<int>(ys.size()) - 1; i >= 1; --i) { // NOLINT
192 ys[i] += remaining_space;
193 remaining_space = remaining_space * (i - 1) / i;
194 }
195 break;
196 }
197
199 for (int i = static_cast<int>(ys.size()) - 1; i >= 0; --i) { // NOLINT
200 ys[i] += remaining_space * (2 * i + 1) / (2 * i + 2);
201 remaining_space = remaining_space * (2 * i) / (2 * i + 2);
202 }
203 break;
204 }
205
207 for (int i = static_cast<int>(ys.size()) - 1; i >= 0; --i) { // NOLINT
208 ys[i] += remaining_space * (i + 1) / (i + 2);
209 remaining_space = remaining_space * (i + 1) / (i + 2);
210 }
211 break;
212 }
213 }
214
215 // [Alinear elementos]
216 for (size_t i = 0; i < g.lines.size(); ++i) {
217 auto& element = elements[i];
218 for (auto* block : g.lines[i].blocks) {
219 const bool stretch =
220 block->flex_grow_y != 0 ||
222 const int size =
223 stretch ? element.size : std::min(element.size, block->min_size_y);
224 switch (g.config.align_items) {
226 block->y = ys[i];
227 block->dim_y = size;
228 break;
229 }
230
232 block->y = ys[i] + (element.size - size) / 2;
233 block->dim_y = size;
234 break;
235 }
236
238 block->y = ys[i] + element.size - size;
239 block->dim_y = size;
240 break;
241 }
242
244 block->y = ys[i];
245 block->dim_y = element.size;
246 break;
247 }
248 }
249 }
250 }
251
252 ys.push_back(g.size_y);
253 for (size_t i = 0; i < g.lines.size(); ++i) {
254 g.lines[i].y = ys[i];
255 g.lines[i].dim_y = ys[i + 1] - ys[i];
256 }
257}
258
259void JustifyContent(Global& g) {
260 for (auto& line : g.lines) {
261 Block* last = line.blocks.back();
262 int remaining_space = g.size_x - last->x - last->dim_x;
263 switch (g.config.justify_content) {
266 break;
267
269 for (auto* block : line.blocks) {
270 block->x += remaining_space;
271 }
272 break;
273 }
274
276 for (auto* block : line.blocks) {
277 block->x += remaining_space / 2;
278 }
279 break;
280 }
281
283 for (int i = (int)line.blocks.size() - 1; i >= 1; --i) {
284 line.blocks[i]->x += remaining_space;
285 remaining_space = remaining_space * (i - 1) / i;
286 }
287 break;
288 }
289
291 for (int i = (int)line.blocks.size() - 1; i >= 0; --i) {
292 line.blocks[i]->x += remaining_space * (2 * i + 1) / (2 * i + 2);
293 remaining_space = remaining_space * (2 * i) / (2 * i + 2);
294 }
295 break;
296 }
297
299 for (int i = (int)line.blocks.size() - 1; i >= 0; --i) {
300 line.blocks[i]->x += remaining_space * (i + 1) / (i + 2);
301 remaining_space = remaining_space * (i + 1) / (i + 2);
302 }
303 break;
304 }
305 }
306 }
307}
308
309void Compute1(Global& global);
310void Compute2(Global& global);
311void Compute3(Global& global);
312
313void Compute1(Global& global) {
315 SymmetryX(global);
316 Compute2(global);
317 SymmetryX(global);
318 return;
319 }
320 Compute2(global);
321}
322
323void Compute2(Global& global) {
325 SymmetryY(global);
326 Compute3(global);
327 SymmetryY(global);
328 return;
329 }
330 Compute3(global);
331}
332
333void Compute3(Global& global) {
334 // Paso 1: Disponer todos los elementos en filas:
335 {
336 Line line;
337 int x = 0;
338 for (auto& block : global.blocks) {
339 // ¿Encaja al final de la fila?
340 // ¿No? Entonces necesitamos empezar una nueva:
341 if (x + block.min_size_x > global.size_x) {
342 x = 0;
343 if (!line.blocks.empty()) {
344 global.lines.push_back(std::move(line));
345 }
346 line = Line();
347 }
348
349 block.line = static_cast<int>(global.lines.size());
350 block.line_position = static_cast<int>(line.blocks.size());
351 line.blocks.push_back(&block);
352 x += block.min_size_x + global.config.gap_x;
353 }
354 if (!line.blocks.empty()) {
355 global.lines.push_back(std::move(line));
356 }
357 }
358
359 // Paso 2: Establecer posiciones en el eje X.
360 SetX(global);
361 JustifyContent(global); // Distribuir el espacio restante.
362
363 // Paso 3: Establecer posiciones en el eje Y.
364 SetY(global);
365}
366
367} // namespace
368
369void Compute(Global& global) {
372 SymmetryXY(global);
373 Compute1(global);
374 SymmetryXY(global);
375 return;
376 }
377 Compute1(global);
378}
379
380} // namespace ftxui::flexbox_helper
@ Center
Los elementos se centran a lo largo del eje transversal.
@ FlexStart
Los elementos se colocan al inicio del eje transversal.
@ FlexEnd
Los elementos se colocan al final del eje transversal.
@ SpaceBetween
Los elementos se distribuyen uniformemente en el eje transversal.
@ Stretch
Los elementos se estiran para llenar el eje transversal.
@ Column
Los elementos flex se distribuyen en una columna.
@ Row
Los elementos flex se distribuyen en una fila.
@ RowInversed
Los elementos flex se distribuyen en una fila, pero en orden inverso.
@ NoWrap
Todos los elementos flex intentarán ajustarse en una sola línea.
@ Wrap
Los elementos flex se ajustarán en varias líneas.
@ Center
Los elementos se centran a lo largo del eje transversal.
@ FlexStart
Los elementos se colocan al inicio del eje transversal.
@ FlexEnd
Los elementos se colocan al final del eje transversal.
@ Stretch
Los elementos se estiran para llenar el eje transversal.
JustifyContent justify_content
@ Center
Los elementos se centran a lo largo de la línea.
@ FlexStart
Los elementos se alinean al inicio de la dirección del flexbox.
@ FlexEnd
Los elementos se alinean al final de la dirección del flexbox.
@ SpaceBetween
Los elementos se distribuyen uniformemente en la línea; el primer elemento está al.
@ Stretch
Los elementos se estiran para llenar la línea.
Decorator size(WidthOrHeight, Constraint, int value)
Aplica una restricción al tamaño de un elemento.
FlexboxConfig es una estructura de configuración que define las propiedades de diseño para un contene...
void Compute(std::vector< Element > *elements, int target_size)
void Compute(Global &global)
std::vector< Block * > blocks