FTXUI 6.1.9
C++ functional terminal UI.
Chargement...
Recherche...
Aucune correspondance
flexbox_helper.cpp
Aller à la documentation de ce fichier.
1// Copyright 2021 Arthur Sonzogni. Tous droits réservés.
2// L'utilisation de ce code source est régie par la licence MIT que l'on peut trouver dans
3// le fichier LICENSE.
5
6#include <algorithm> // for max, min
7#include <cstddef> // for size_t
8#include <ftxui/dom/flexbox_config.hpp> // for 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> // for swap, move
10#include <vector>
11
12#include "ftxui/dom/box_helper.hpp" // for 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 // [Align-content]
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 // [Align items]
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 // Étape 1: Disposer tous les éléments en rangées:
335 {
336 Line line;
337 int x = 0;
338 for (auto& block : global.blocks) {
339 // Est-ce que cela rentre à la fin de la rangée ?
340 // Non ? Alors nous devons en commencer une nouvelle :
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 // Étape 2: Définir les positions sur l'axe X.
360 SetX(global);
361 JustifyContent(global); // Distribuer l'espace restant.
362
363 // Étape 3: Définir les positions sur l'axe 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
Les éléments sont centrés le long de l'axe transversal.
@ FlexStart
Les éléments sont placés au début de l'axe transversal.
@ FlexEnd
Les éléments sont placés à la fin de l'axe transversal.
@ Stretch
Les éléments sont étirés pour remplir l'axe transversal.
@ Column
Les éléments flexibles sont disposés en colonne.
@ Row
Les éléments flexibles sont disposés en ligne.
@ Center
Les éléments sont centrés le long de l'axe transversal.
@ FlexStart
Les éléments sont placés au début de l'axe transversal.
@ FlexEnd
Les éléments sont placés à la fin de l'axe transversal.
@ Stretch
Les éléments sont étirés pour remplir l'axe transversal.
JustifyContent justify_content
@ Center
Les éléments sont centrés le long de la ligne.
@ FlexStart
Les éléments sont alignés au début de la direction du flexbox.
@ FlexEnd
Les éléments sont alignés à la fin de la direction du flexbox.
@ Stretch
Les éléments sont étirés pour remplir la ligne.
Decorator size(WidthOrHeight, Constraint, int value)
Applique une contrainte sur la taille d'un élément.
FlexboxConfig est une structure de configuration qui définit les propriétés de mise en page pour un c...
void Compute(std::vector< Element > *elements, int target_size)
void Compute(Global &global)
std::vector< Block * > blocks