FTXUI  2.0.0
C++ functional terminal UI.
Loading...
Searching...
No Matches
flexbox_helper.cpp
Go to the documentation of this file.
2
3#include <stddef.h> // for size_t
4#include <algorithm> // for min, max
5#include <memory> // for allocator_traits<>::value_type
6#include <utility> // for swap, move
7
8#include "ftxui/dom/box_helper.hpp" // for Element, Compute
9
10namespace ftxui {
11namespace flexbox_helper {
12
13namespace {
14void SymmetryXY(FlexboxConfig& c) {
15 std::swap(c.gap_x, c.gap_y);
16 switch (c.direction) {
19 break;
22 break;
25 break;
28 break;
29 }
30}
31
32void SymmetryX(FlexboxConfig& c) {
33 switch (c.direction) {
36 break;
39 break;
40 default:
41 break;
42 }
43}
44
45void SymmetryY(FlexboxConfig& c) {
46 switch (c.wrap) {
48 break;
51 break;
54 break;
55 }
56}
57
58void SymmetryXY(Global& g) {
59 SymmetryXY(g.config);
60 std::swap(g.size_x, g.size_y);
61 for (auto& b : g.blocks) {
62 std::swap(b.min_size_x, b.min_size_y);
63 std::swap(b.flex_grow_x, b.flex_grow_y);
64 std::swap(b.flex_shrink_x, b.flex_shrink_y);
65 std::swap(b.x, b.y);
66 std::swap(b.dim_x, b.dim_y);
67 }
68}
69
70void SymmetryX(Global& g) {
71 SymmetryX(g.config);
72 for (auto& b : g.blocks) {
73 b.x = g.size_x - b.x - b.dim_x;
74 }
75}
76
77void SymmetryY(Global& g) {
78 SymmetryY(g.config);
79 for (auto& b : g.blocks) {
80 b.y = g.size_y - b.y - b.dim_y;
81 }
82}
83
84struct Line {
85 std::vector<Block*> blocks;
86};
87
88void SetX(Global& global, std::vector<Line> lines) {
89 for (auto& line : lines) {
90 std::vector<box_helper::Element> elements;
91 for (auto* block : line.blocks) {
92 box_helper::Element element;
93 element.min_size = block->min_size_x;
94 element.flex_grow =
95 block->flex_grow_x || global.config.justify_content ==
97 element.flex_shrink = block->flex_shrink_x;
98 elements.push_back(element);
99 }
100
102 &elements,
103 global.size_x - global.config.gap_x * (line.blocks.size() - 1));
104
105 int x = 0;
106 for (size_t i = 0; i < line.blocks.size(); ++i) {
107 line.blocks[i]->dim_x = elements[i].size;
108 line.blocks[i]->x = x;
109 x += elements[i].size;
110 x += global.config.gap_x;
111 }
112 }
113}
114
115void SetY(Global& g, std::vector<Line> lines) {
116 std::vector<box_helper::Element> elements;
117 for (auto& line : lines) {
118 box_helper::Element element;
119 element.flex_shrink = line.blocks.front()->flex_shrink_y;
120 element.flex_grow = line.blocks.front()->flex_grow_y;
121 for (auto* block : line.blocks) {
122 element.min_size = std::max(element.min_size, block->min_size_y);
123 element.flex_shrink = std::min(element.flex_shrink, block->flex_shrink_y);
124 element.flex_grow = std::min(element.flex_grow, block->flex_grow_y);
125 }
126 elements.push_back(element);
127 }
128
129 // box_helper::Compute(&elements, g.size_y);
130 box_helper::Compute(&elements, 10000);
131
132 // [Align-content]
133 std::vector<int> ys(elements.size());
134 int y = 0;
135 for (size_t i = 0; i < elements.size(); ++i) {
136 ys[i] = y;
137 y += elements[i].size;
138 y += g.config.gap_y;
139 }
140 int remaining_space = std::max(0, g.size_y - y);
141 switch (g.config.align_content) {
143 } break;
144
146 for (size_t i = 0; i < ys.size(); ++i)
147 ys[i] += remaining_space;
148 } break;
149
151 for (size_t i = 0; i < ys.size(); ++i)
152 ys[i] += remaining_space / 2;
153 } break;
154
156 for (int i = ys.size() - 1; i >= 0; --i) {
157 int shifted = remaining_space * (i + 0) / (i + 1);
158 ys[i] += shifted;
159 int consumed = remaining_space - shifted;
160 elements[i].size += consumed;
161 remaining_space -= consumed;
162 }
163 } break;
164
166 for (int i = ys.size() - 1; i >= 1; --i) {
167 ys[i] += remaining_space;
168 remaining_space = remaining_space * (i - 1) / i;
169 }
170 } break;
171
173 for (int i = ys.size() - 1; i >= 0; --i) {
174 ys[i] += remaining_space * (2 * i + 1) / (2 * i + 2);
175 remaining_space = remaining_space * (2 * i) / (2 * i + 2);
176 }
177 } break;
178
180 for (int i = ys.size() - 1; i >= 0; --i) {
181 ys[i] += remaining_space * (i + 1) / (i + 2);
182 remaining_space = remaining_space * (i + 1) / (i + 2);
183 }
184 } break;
185 }
186
187 // [Align items]
188 for (size_t i = 0; i < lines.size(); ++i) {
189 auto& element = elements[i];
190 for (auto* block : lines[i].blocks) {
191 bool stretch =
192 block->flex_grow_y ||
194 int size =
195 stretch ? element.size : std::min(element.size, block->min_size_y);
196 switch (g.config.align_items) {
198 block->y = ys[i];
199 block->dim_y = size;
200 } break;
201
203 block->y = ys[i] + (element.size - size) / 2;
204 block->dim_y = size;
205 } break;
206
208 block->y = ys[i] + element.size - size;
209 block->dim_y = size;
210 } break;
211
213 block->y = ys[i];
214 block->dim_y = element.size;
215 } break;
216 }
217 }
218 }
219}
220
221void JustifyContent(Global& g, std::vector<Line> lines) {
222 for (auto& line : lines) {
223 Block* last = line.blocks.back();
224 int remaining_space = g.size_x - last->x - last->dim_x;
225 switch (g.config.justify_content) {
228 break;
229
231 for (auto* block : line.blocks)
232 block->x += remaining_space;
233 } break;
234
236 for (auto* block : line.blocks)
237 block->x += remaining_space / 2;
238 } break;
239
241 for (int i = line.blocks.size() - 1; i >= 1; --i) {
242 line.blocks[i]->x += remaining_space;
243 remaining_space = remaining_space * (i - 1) / i;
244 }
245 } break;
246
248 for (int i = line.blocks.size() - 1; i >= 0; --i) {
249 line.blocks[i]->x += remaining_space * (2 * i + 1) / (2 * i + 2);
250 remaining_space = remaining_space * (2 * i) / (2 * i + 2);
251 }
252 } break;
253
255 for (int i = line.blocks.size() - 1; i >= 0; --i) {
256 line.blocks[i]->x += remaining_space * (i + 1) / (i + 2);
257 remaining_space = remaining_space * (i + 1) / (i + 2);
258 }
259 } break;
260 }
261 }
262}
263} // namespace
264
265void Compute(Global& global) {
268 SymmetryXY(global);
269 Compute(global);
270 SymmetryXY(global);
271 return;
272 }
273
275 SymmetryX(global);
276 Compute(global);
277 SymmetryX(global);
278 return;
279 }
280
282 SymmetryY(global);
283 Compute(global);
284 SymmetryY(global);
285 return;
286 }
287
288 // Step 1: Lay out every elements into rows:
289 std::vector<Line> lines;
290 {
291 Line line;
292 int x = 0;
293 for (auto& block : global.blocks) {
294 // Does it fit the end of the row?
295 // No? Then we need to start a new one:
296 if (x + block.min_size_x > global.size_x) {
297 x = 0;
298 if (!line.blocks.empty())
299 lines.push_back(std::move(line));
300 line = Line();
301 }
302
303 block.line = lines.size();
304 block.line_position = line.blocks.size();
305 line.blocks.push_back(&block);
306 x += block.min_size_x + global.config.gap_x;
307 }
308 if (!line.blocks.empty())
309 lines.push_back(std::move(line));
310 }
311
312 // Step 2: Set positions on the X axis.
313 SetX(global, lines);
314 JustifyContent(global, lines); // Distribute remaining space.
315
316 // Step 3: Set positions on the Y axis.
317 SetY(global, lines);
318}
319
320} // namespace flexbox_helper
321} // namespace ftxui
322
323// Copyright 2021 Arthur Sonzogni. All rights reserved.
324// Use of this source code is governed by the MIT license that can be found in
325// the LICENSE file.
void Compute(std::vector< Element > *elements, int target_size)
void Compute(Global &global)
Decorator size(Direction, Constraint, int value)
Apply a constraint on the size of an element.
Definition size.cpp:86
@ Center
items are centered along the cross axis.
@ FlexStart
items are placed at the start of the cross axis.
@ FlexEnd
items are placed at the end of the cross axis.
@ SpaceBetween
items are evenly distributed in the cross axis.
@ Stretch
items are stretched to fill the cross axis.
@ Column
Flex items are laid out in a column.
@ Row
Flex items are laid out in a row.
@ RowInversed
Flex items are laid out in a row, but in reverse order.
@ NoWrap
Flex items will all try to fit onto one line.
@ Wrap
Flex items will wrap onto multiple lines.
@ Center
items are centered along the cross axis.
@ FlexStart
items are placed at the start of the cross axis.
@ FlexEnd
items are placed at the end of the cross axis.
@ Stretch
items are stretched to fill the cross axis.
JustifyContent justify_content
@ Center
Items are centered along the line.
@ FlexStart
Items are aligned to the start of flexbox's direction.
@ FlexEnd
Items are aligned to the end of flexbox's direction.
@ SpaceBetween
Items are evenly distributed in the line; first item is on the start.
@ Stretch
Items are stretched to fill the line.