26 const std::vector<FlexItemSpec> &items) {
28 res.
items.resize(items.size());
29 if (availMain < 0.f) availMain = 0.f;
30 if (availCross < 0.f) availCross = 0.f;
32 const int n = int(items.size());
33 std::vector<float> mainSize(
size_t(
n), 0.f);
34 std::vector<float> crossSize(
size_t(
n), 0.f);
35 std::vector<float> mainPos(
size_t(
n), 0.f);
36 std::vector<float> crossPos(
size_t(
n), 0.f);
38 float flowTotal = 0.f;
42 for (
int i = 0; i <
n; ++i) {
46 : (
s.percentMain > 0.f ?
s.percentMain * availMain :
s.basisMain);
47 m = clampV(
m,
s.minMain,
s.maxMain);
48 float c =
s.explicitCross > 0.f
50 : (
s.percentCross > 0.f ?
s.percentCross * availCross :
s.basisCross);
51 c = clampV(
c,
s.minCross,
s.maxCross);
52 mainSize[size_t(i)] =
m;
53 crossSize[size_t(i)] =
c;
55 if (
s.absolute)
continue;
56 growSum += effectiveGrow(
s);
57 flowTotal +=
m +
s.marginBefore +
s.marginAfter;
61 const int gapCount = std::max(0, flowCount - 1);
62 float total = flowTotal + float(gapCount) * gap;
63 float freeSpace = availMain - total;
64 if (freeSpace < 0.f) freeSpace = 0.f;
69 for (
int i = 0; i <
n; ++i) {
71 if (
s.absolute)
continue;
72 const float g = effectiveGrow(
s);
73 if (g > 0.f) mainSize[size_t(i)] += freeSpace * (g / growSum);
75 }
else if (freeSpace > 0.f && flowCount > 0) {
78 leading = freeSpace * 0.5f;
84 if (gapCount > 0) between = gap + freeSpace / float(gapCount);
88 const float edge = freeSpace / float(flowCount * 2);
90 between = gap + edge * 2.f;
100 for (
int i = 0; i <
n; ++i) {
104 s.
anchorMain * availMain +
s.posMain -
s.anchorMain * mainSize[size_t(i)];
107 mainPos[size_t(i)] = cur +
s.marginBefore;
108 cur +=
s.marginBefore + mainSize[size_t(i)] +
s.marginAfter + between;
110 const float contentMain = flowCount > 0 ? cur - between : 0.f;
112 float contentCross = 0.f;
113 for (
int i = 0; i <
n; ++i) {
116 crossPos[size_t(i)] =
117 s.
anchorCross * availCross +
s.posCross -
s.anchorCross * crossSize[size_t(i)];
118 contentCross = std::max(contentCross,
119 crossPos[
size_t(i)] + crossSize[
size_t(i)] +
123 const float cb =
s.marginCrossBefore;
124 const float ca =
s.marginCrossAfter;
125 const bool stretch =
s.alignSelf >= 0
128 if (stretch &&
s.explicitCross <= 0.f &&
s.percentCross <= 0.f) {
129 float c = availCross - cb - ca;
130 if (
c < 0.f)
c = 0.f;
131 crossSize[size_t(i)] =
c;
133 switch (containerAlign) {
135 crossPos[size_t(i)] = (availCross - crossSize[size_t(i)] - cb - ca) * 0.5f + cb;
138 crossPos[size_t(i)] = availCross - crossSize[size_t(i)] - ca;
143 crossPos[size_t(i)] = cb;
146 contentCross = std::max(contentCross,
147 crossPos[
size_t(i)] + crossSize[
size_t(i)] + ca);
150 for (
int i = 0; i <
n; ++i) {
153 r.
x = mainPos[size_t(i)];
154 r.
y = crossPos[size_t(i)];
155 r.
w = mainSize[size_t(i)];
156 r.
h = crossSize[size_t(i)];
158 r.
x = crossPos[size_t(i)];
159 r.
y = mainPos[size_t(i)];
160 r.
w = crossSize[size_t(i)];
161 r.
h = mainSize[size_t(i)];
175 bool sameRow =
false;
176 const ImGuiStyle &style = ImGui::GetStyle();
177 int index = firstChild;
178 while (index >= 0 && index <
int(tree.
nodes.size())) {
180 const int next =
n.nextSibling;
186 const float w =
n.measuredW +
n.marginL +
n.marginR;
187 const float h =
n.measuredH +
n.marginT +
n.marginB;
189 rowW += style.ItemSpacing.x +
w;
191 if (rowH > 0.f) totalH += style.ItemSpacing.y;
196 rowH = std::max(rowH,
h);
197 maxW = std::max(maxW, rowW);
203 if (rowH > 0.f) totalH += rowH;
204 if (outW) *outW = maxW;
205 if (outH) *outH = totalH;
209 if (index < 0 || index >=
int(tree.
nodes.size()))
return;
213 const ImGuiStyle &style = ImGui::GetStyle();
217 const ImVec2 t =
n.wrapWidth > 0.f
218 ? ImGui::CalcTextSize(
n.text.c_str(),
nullptr,
false,
n.wrapWidth)
219 : ImGui::CalcTextSize(
n.text.c_str());
226 n.measuredH = ImGui::GetFrameHeight();
230 const char *label =
n.text.empty() ?
"Button" :
n.text.c_str();
231 const ImVec2 t = ImGui::CalcTextSize(label);
232 n.measuredW = t.x + style.FramePadding.x * 2.f;
233 n.measuredH = ImGui::GetFrameHeight();
237 const char *label =
n.text.empty() ?
"Check" :
n.text.c_str();
238 const ImVec2 t = ImGui::CalcTextSize(label);
239 n.measuredW = ImGui::GetFrameHeight() + style.ItemInnerSpacing.x + t.x;
240 n.measuredH = ImGui::GetFrameHeight();
246 n.measuredH = ImGui::GetFrameHeight();
250 n.measuredH = ImGui::GetFrameHeight();
254 n.measuredW =
n.sizeX > 0.f ?
n.sizeX : 32.f;
255 n.measuredH =
n.sizeY > 0.f ?
n.sizeY : 32.f;
258 n.measuredW = style.ItemSpacing.x;
262 n.measuredW =
n.sizeX > 0.f ?
n.sizeX : 0.f;
263 n.measuredH =
n.sizeY > 0.f ?
n.sizeY : 0.f;
266 n.measuredW =
n.sizeX > 0.f ?
n.sizeX : 80.f;
267 n.measuredH =
n.sizeY > 0.f ?
n.sizeY : 120.f;
270 n.measuredW =
n.sizeX > 0.f ?
n.sizeX : 0.f;
271 n.measuredH =
n.sizeY > 0.f ?
n.sizeY : 120.f;
274 n.measuredW =
n.sizeX > 0.f ?
n.sizeX : 0.f;
275 n.measuredH =
n.sizeY > 0.f ?
n.sizeY : 240.f;
278 const char *label =
n.text.empty() ?
"Section" :
n.text.c_str();
279 const ImVec2 t = ImGui::CalcTextSize(label);
280 n.measuredW = t.x + style.FramePadding.x * 2.f + 18.f;
281 n.measuredH = ImGui::GetFrameHeight();
283 float w = 0.f,
h = 0.f;
285 n.measuredW = std::max(
n.measuredW,
w);
291 float w = 0.f,
h = 0.f;
293 n.measuredW =
w +
n.paddingL +
n.paddingR;
294 n.measuredH =
h +
n.paddingT +
n.paddingB;
300 float crossMax = 0.f;
302 for (
int c =
n.firstChild;
c >= 0;
c = tree.
nodes[size_t(
c)].nextSibling) {
313 mainSum +=
m + mb + ma;
314 crossMax = std::max(crossMax, cm + cb + ca);
317 const float gap =
n.gap >= 0.f ?
n.gap : (
row ? style.ItemSpacing.x : style.ItemSpacing.y);
318 const float padMain =
row ?
n.
paddingL +
n.paddingR :
n.paddingT +
n.paddingB;
319 const float padCross =
row ?
n.
paddingT +
n.paddingB :
n.paddingL +
n.paddingR;
320 const float mainSize = mainSum + float(std::max(0, count - 1)) * gap + padMain;
321 const float crossSize = crossMax + padCross;
322 n.measuredW =
row ? mainSize : crossSize;
323 n.measuredH =
row ? crossSize : mainSize;
327 float w = 0.f,
h = 0.f;
329 n.measuredW =
w +
n.paddingL +
n.paddingR;
330 n.measuredH =
h +
n.paddingT +
n.paddingB;
339 if (
n.sizeX > 0.f)
n.measuredW =
n.sizeX;
340 if (
n.sizeY > 0.f)
n.measuredH =
n.sizeY;
342 if (
n.minSizeX > 0.f)
n.measuredW = std::max(
n.measuredW,
n.minSizeX);
343 if (
n.minSizeY > 0.f)
n.measuredH = std::max(
n.measuredH,
n.minSizeY);
344 if (
n.maxSizeX > 0.f)
n.measuredW = std::min(
n.measuredW,
n.maxSizeX);
345 if (
n.maxSizeY > 0.f)
n.measuredH = std::min(
n.measuredH,
n.maxSizeY);
FlexResult flexArrange(bool row, float gap, float availMain, float availCross, FlexAlign containerAlign, FlexJustify justify, const std::vector< FlexItemSpec > &items)
WidgetDesc child(std::string id, std::vector< WidgetDesc > children, float width, float height)
Scrollable child region with an explicit size.