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. All rights reserved.
2// このソースコードの使用は、LICENSEファイルに記載されているMITライセンスに準拠します。
4
5#include <algorithm> // for max, min
6#include <cstddef> // for size_t
7#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
8#include <utility> // for swap, move
9#include <vector>
10
11#include "ftxui/dom/box_helper.hpp" // for Element, Compute
12
14
15namespace {
16void SymmetryXY(FlexboxConfig& c) {
17 std::swap(c.gap_x, c.gap_y);
18 switch (c.direction) {
21 break;
24 break;
27 break;
30 break;
31 }
32}
33
34void SymmetryX(FlexboxConfig& c) {
35 switch (c.direction) {
38 break;
41 break;
42 default:
43 break;
44 }
45}
46
47void SymmetryY(FlexboxConfig& c) {
48 switch (c.wrap) {
50 break;
53 break;
56 break;
57 }
58}
59
60void SymmetryXY(Global& g) {
61 SymmetryXY(g.config);
62 std::swap(g.size_x, g.size_y);
63 for (auto& b : g.blocks) {
64 std::swap(b.min_size_x, b.min_size_y);
65 std::swap(b.flex_grow_x, b.flex_grow_y);
66 std::swap(b.flex_shrink_x, b.flex_shrink_y);
67 std::swap(b.x, b.y);
68 std::swap(b.dim_x, b.dim_y);
69 }
70 for (auto& l : g.lines) {
71 std::swap(l.x, l.y);
72 std::swap(l.dim_x, l.dim_y);
73 }
74}
75
76void SymmetryX(Global& g) {
77 SymmetryX(g.config);
78 for (auto& b : g.blocks) {
79 b.x = g.size_x - b.x - b.dim_x;
80 }
81 for (auto& l : g.lines) {
82 l.x = g.size_x - l.x - l.dim_x;
83 }
84}
85
86void SymmetryY(Global& g) {
87 SymmetryY(g.config);
88 for (auto& b : g.blocks) {
89 b.y = g.size_y - b.y - b.dim_y;
90 }
91 for (auto& l : g.lines) {
92 l.y = g.size_y - l.y - l.dim_y;
93 }
94}
95
96void SetX(Global& global) {
97 for (auto& line : global.lines) {
98 std::vector<box_helper::Element> elements;
99 elements.reserve(line.blocks.size());
100 for (auto* block : line.blocks) {
101 box_helper::Element element;
102 element.min_size = block->min_size_x;
103 element.flex_grow =
104 block->flex_grow_x != 0 || global.config.justify_content ==
106 ? 1
107 : 0;
108 element.flex_shrink = block->flex_shrink_x;
109 elements.push_back(element);
110 }
111
113 &elements,
114 global.size_x - global.config.gap_x * (int(line.blocks.size()) - 1));
115
116 int x = 0;
117 for (size_t i = 0; i < line.blocks.size(); ++i) {
118 line.blocks[i]->x = x;
119 line.blocks[i]->dim_x = elements[i].size;
120 x += elements[i].size;
121 x += global.config.gap_x;
122 }
123 }
124
125 for (auto& line : global.lines) {
126 line.x = 0;
127 line.dim_x = global.size_x;
128 }
129}
130
131// NOLINTNEXTLINE(readability-function-cognitive-complexity)
132void SetY(Global& g) {
133 std::vector<box_helper::Element> elements;
134 elements.reserve(g.lines.size());
135 for (auto& line : g.lines) {
136 box_helper::Element element;
137 element.flex_shrink = line.blocks.front()->flex_shrink_y;
138 element.flex_grow = line.blocks.front()->flex_grow_y;
139 for (auto* block : line.blocks) {
140 element.min_size = std::max(element.min_size, block->min_size_y);
141 element.flex_shrink = std::min(element.flex_shrink, block->flex_shrink_y);
142 element.flex_grow = std::min(element.flex_grow, block->flex_grow_y);
143 }
144 elements.push_back(element);
145 }
146
147 // box_helper::Compute(&elements, g.size_y);
148 box_helper::Compute(&elements, 10000); // NOLINT
149
150 // [Align-content]
151 std::vector<int> ys(elements.size());
152 int y = 0;
153 for (size_t i = 0; i < elements.size(); ++i) {
154 ys[i] = y;
155 y += elements[i].size;
156 y += g.config.gap_y;
157 }
158 int remaining_space = std::max(0, g.size_y - y);
159 switch (g.config.align_content) {
161 break;
162 }
163
165 for (size_t i = 0; i < ys.size(); ++i) { // NOLINT
166 ys[i] += remaining_space;
167 }
168 break;
169 }
170
172 for (size_t i = 0; i < ys.size(); ++i) { // NOLINT
173 ys[i] += remaining_space / 2;
174 }
175 break;
176 }
177
179 for (int i = static_cast<int>(ys.size()) - 1; i >= 0; --i) { // NOLINT
180 const int shifted = remaining_space * (i + 0) / (i + 1);
181 ys[i] += shifted;
182 const int consumed = remaining_space - shifted;
183 elements[i].size += consumed;
184 remaining_space -= consumed;
185 }
186 break;
187 }
188
190 for (int i = static_cast<int>(ys.size()) - 1; i >= 1; --i) { // NOLINT
191 ys[i] += remaining_space;
192 remaining_space = remaining_space * (i - 1) / i;
193 }
194 break;
195 }
196
198 for (int i = static_cast<int>(ys.size()) - 1; i >= 0; --i) { // NOLINT
199 ys[i] += remaining_space * (2 * i + 1) / (2 * i + 2);
200 remaining_space = remaining_space * (2 * i) / (2 * i + 2);
201 }
202 break;
203 }
204
206 for (int i = static_cast<int>(ys.size()) - 1; i >= 0; --i) { // NOLINT
207 ys[i] += remaining_space * (i + 1) / (i + 2);
208 remaining_space = remaining_space * (i + 1) / (i + 2);
209 }
210 break;
211 }
212 }
213
214 // [Align items]
215 for (size_t i = 0; i < g.lines.size(); ++i) {
216 auto& element = elements[i];
217 for (auto* block : g.lines[i].blocks) {
218 const bool stretch =
219 block->flex_grow_y != 0 ||
221 const int size =
222 stretch ? element.size : std::min(element.size, block->min_size_y);
223 switch (g.config.align_items) {
225 block->y = ys[i];
226 block->dim_y = size;
227 break;
228 }
229
231 block->y = ys[i] + (element.size - size) / 2;
232 block->dim_y = size;
233 break;
234 }
235
237 block->y = ys[i] + element.size - size;
238 block->dim_y = size;
239 break;
240 }
241
243 block->y = ys[i];
244 block->dim_y = element.size;
245 break;
246 }
247 }
248 }
249 }
250
251 ys.push_back(g.size_y);
252 for (size_t i = 0; i < g.lines.size(); ++i) {
253 g.lines[i].y = ys[i];
254 g.lines[i].dim_y = ys[i + 1] - ys[i];
255 }
256}
257
258void JustifyContent(Global& g) {
259 for (auto& line : g.lines) {
260 Block* last = line.blocks.back();
261 int remaining_space = g.size_x - last->x - last->dim_x;
262 switch (g.config.justify_content) {
265 break;
266
268 for (auto* block : line.blocks) {
269 block->x += remaining_space;
270 }
271 break;
272 }
273
275 for (auto* block : line.blocks) {
276 block->x += remaining_space / 2;
277 }
278 break;
279 }
280
282 for (int i = (int)line.blocks.size() - 1; i >= 1; --i) {
283 line.blocks[i]->x += remaining_space;
284 remaining_space = remaining_space * (i - 1) / i;
285 }
286 break;
287 }
288
290 for (int i = (int)line.blocks.size() - 1; i >= 0; --i) {
291 line.blocks[i]->x += remaining_space * (2 * i + 1) / (2 * i + 2);
292 remaining_space = remaining_space * (2 * i) / (2 * i + 2);
293 }
294 break;
295 }
296
298 for (int i = (int)line.blocks.size() - 1; i >= 0; --i) {
299 line.blocks[i]->x += remaining_space * (i + 1) / (i + 2);
300 remaining_space = remaining_space * (i + 1) / (i + 2);
301 }
302 break;
303 }
304 }
305 }
306}
307
308void Compute1(Global& global);
309void Compute2(Global& global);
310void Compute3(Global& global);
311
312void Compute1(Global& global) {
314 SymmetryX(global);
315 Compute2(global);
316 SymmetryX(global);
317 return;
318 }
319 Compute2(global);
320}
321
322void Compute2(Global& global) {
324 SymmetryY(global);
325 Compute3(global);
326 SymmetryY(global);
327 return;
328 }
329 Compute3(global);
330}
331
332void Compute3(Global& global) {
333 // ステップ1: すべての要素を行に配置します。
334 {
335 Line line;
336 int x = 0;
337 for (auto& block : global.blocks) {
338 // 行の最後に収まりますか?
339 // いいえ?その場合、新しい行を開始する必要があります。
340 if (x + block.min_size_x > global.size_x) {
341 x = 0;
342 if (!line.blocks.empty()) {
343 global.lines.push_back(std::move(line));
344 }
345 line = Line();
346 }
347
348 block.line = static_cast<int>(global.lines.size());
349 block.line_position = static_cast<int>(line.blocks.size());
350 line.blocks.push_back(&block);
351 x += block.min_size_x + global.config.gap_x;
352 }
353 if (!line.blocks.empty()) {
354 global.lines.push_back(std::move(line));
355 }
356 }
357
358 // ステップ2: X軸上の位置を設定します。
359 SetX(global);
360 JustifyContent(global); // 残りのスペースを分配します。
361
362 // ステップ3: Y軸上の位置を設定します。
363 SetY(global);
364}
365
366} // namespace
367
368void Compute(Global& global) {
371 SymmetryXY(global);
372 Compute1(global);
373 SymmetryXY(global);
374 return;
375 }
376 Compute1(global);
377}
378
379} // namespace ftxui::flexbox_helper
@ Center
アイテムは交差軸の中央に配置されます。
@ FlexStart
アイテムは交差軸の開始位置に配置されます。
@ FlexEnd
アイテムは交差軸の終了位置に配置されます。
@ SpaceBetween
アイテムは交差軸に沿って均等に分配されます。
@ Stretch
アイテムは交差軸を埋めるように引き伸ばされます。
@ Column
フレックスアイテムは列に配置されます。
@ Row
フレックスアイテムは行に配置されます。
@ RowInversed
フレックスアイテムは行に配置されますが、逆順になります。
@ NoWrap
フレックスアイテムはすべて1行に収まろうとします。
@ Wrap
フレックスアイテムは複数行に折り返されます。
@ Center
アイテムは交差軸の中央に配置されます。
@ FlexStart
アイテムは交差軸の開始位置に配置されます。
@ FlexEnd
アイテムは交差軸の終了位置に配置されます。
@ Stretch
アイテムは交差軸を埋めるように引き伸ばされます。
JustifyContent justify_content
@ SpaceEvenly
アイテムは、任意の2つのアイテム間のスペース(および端までのスペース)が均等になるように分配されます。
@ Center
アイテムは行の中央に配置されます。
@ FlexStart
アイテムはflexboxの方向の開始位置に揃えられます。
@ FlexEnd
アイテムはflexboxの方向の終了位置に揃えられます。
@ SpaceBetween
アイテムは行に沿って均等に分配されます。最初のアイテムは開始行に、最後のアイテムは終了行に配置されます。
@ Stretch
アイテムは行を埋めるように引き伸ばされます。
FlexboxConfigは、flexboxコンテナのレイアウトプロパティを定義する構成構造体です。
void Compute(std::vector< Element > *elements, int target_size)
void Compute(Global &global)
return size
Definition string.cpp:1516
std::vector< Block * > blocks