yoga-layout-python 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. yoga/YGConfig.py +92 -0
  2. yoga/YGEnums.py +404 -0
  3. yoga/YGMacros.py +9 -0
  4. yoga/YGNode.py +367 -0
  5. yoga/YGNodeLayout.py +81 -0
  6. yoga/YGNodeStyle.py +876 -0
  7. yoga/YGPixelGrid.py +42 -0
  8. yoga/YGValue.py +49 -0
  9. yoga/__init__.py +16 -0
  10. yoga/algorithm/AbsoluteLayout.py +417 -0
  11. yoga/algorithm/Align.py +34 -0
  12. yoga/algorithm/Baseline.py +54 -0
  13. yoga/algorithm/BoundAxis.py +55 -0
  14. yoga/algorithm/Cache.py +93 -0
  15. yoga/algorithm/CalculateLayout.py +1651 -0
  16. yoga/algorithm/FlexDirection.py +76 -0
  17. yoga/algorithm/FlexLine.py +130 -0
  18. yoga/algorithm/PixelGrid.py +56 -0
  19. yoga/algorithm/SizingMode.py +39 -0
  20. yoga/algorithm/TrailingPosition.py +34 -0
  21. yoga/algorithm/__init__.py +18 -0
  22. yoga/config/Config.py +137 -0
  23. yoga/config/__init__.py +9 -0
  24. yoga/debug/AssertFatal.py +24 -0
  25. yoga/debug/Log.py +49 -0
  26. yoga/debug/__init__.py +10 -0
  27. yoga/event/__init__.py +9 -0
  28. yoga/event/event.py +123 -0
  29. yoga/node/CachedMeasurement.py +51 -0
  30. yoga/node/LayoutResults.py +225 -0
  31. yoga/node/LayoutableChildren.py +79 -0
  32. yoga/node/Node.py +566 -0
  33. yoga/node/__init__.py +11 -0
  34. yoga/numeric/Comparison.py +46 -0
  35. yoga/numeric/FloatMath.py +24 -0
  36. yoga/numeric/FloatOptional.py +65 -0
  37. yoga/numeric/__init__.py +10 -0
  38. yoga/style/GridLine.py +44 -0
  39. yoga/style/GridTrack.py +47 -0
  40. yoga/style/SmallValueBuffer.py +133 -0
  41. yoga/style/Style.py +763 -0
  42. yoga/style/StyleLength.py +88 -0
  43. yoga/style/StyleSizeLength.py +117 -0
  44. yoga/style/StyleValueHandle.py +98 -0
  45. yoga/style/StyleValuePool.py +191 -0
  46. yoga/style/__init__.py +16 -0
  47. yoga_layout_python-0.1.0.dist-info/METADATA +158 -0
  48. yoga_layout_python-0.1.0.dist-info/RECORD +51 -0
  49. yoga_layout_python-0.1.0.dist-info/WHEEL +5 -0
  50. yoga_layout_python-0.1.0.dist-info/licenses/LICENSE +21 -0
  51. yoga_layout_python-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1651 @@
1
+ """
2
+ Copyright (c) Meta Platforms, Inc. and affiliates.
3
+
4
+ This source code is licensed under the MIT license found in the
5
+ LICENSE file in the root directory of this source tree.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from math import isnan
11
+
12
+ from ..algorithm.AbsoluteLayout import layoutAbsoluteDescendants
13
+ from ..algorithm.Align import fallbackAlignment, resolveChildAlignment
14
+ from ..algorithm.Baseline import calculateBaseline, isBaselineLayout
15
+ from ..algorithm.BoundAxis import boundAxis, boundAxisWithinMinAndMax, paddingAndBorderForAxis
16
+ from ..algorithm.Cache import canUseCachedMeasurement
17
+ from ..algorithm.FlexDirection import dimension, flexStartEdge, isRow, resolveCrossDirection, resolveDirection
18
+ from ..algorithm.FlexLine import calculateFlexLine
19
+ from ..algorithm.PixelGrid import roundLayoutResultsToPixelGrid
20
+ from ..algorithm.SizingMode import SizingMode
21
+ from ..algorithm.TrailingPosition import needsTrailingPosition, setChildTrailingPosition
22
+ from ..YGEnums import (
23
+ YGAlign,
24
+ YGDimension,
25
+ YGDirection,
26
+ YGDisplay,
27
+ YGEdge,
28
+ YGErrata,
29
+ YGFlexDirection,
30
+ YGJustify,
31
+ YGMeasureMode,
32
+ YGOverflow,
33
+ YGPositionType,
34
+ YGWrap,
35
+ YGExperimentalFeature,
36
+ )
37
+ from ..event.event import (
38
+ Event,
39
+ EventData,
40
+ LayoutData,
41
+ LayoutPassEndData,
42
+ LayoutPassReason,
43
+ LayoutType,
44
+ MeasureCallbackEndData,
45
+ NodeLayoutData,
46
+ )
47
+ from ..node.LayoutResults import LayoutResults
48
+ from ..node.Node import Node
49
+ from ..numeric.FloatMath import float32, floatDivision
50
+ from ..numeric.Comparison import inexactEquals, isDefined, isUndefined, maxOrDefined, minOrDefined
51
+ from ..numeric.FloatOptional import FloatOptional, maxOrDefined as maxOrDefinedFloatOptional
52
+
53
+
54
+ gCurrentGenerationCount = 0
55
+
56
+
57
+ def constrainMaxSizeForMode(
58
+ node: Node,
59
+ direction: YGDirection,
60
+ axis: YGFlexDirection,
61
+ ownerAxisSize: float,
62
+ ownerWidth: float,
63
+ mode: SizingMode,
64
+ size: float,
65
+ ) -> tuple[SizingMode, float]:
66
+ maxSize = node.style().resolvedMaxDimension(
67
+ direction,
68
+ YGDimension.YGDimensionWidth if isRow(axis) else YGDimension.YGDimensionHeight,
69
+ ownerAxisSize,
70
+ ownerWidth,
71
+ ) + FloatOptional(node.style().computeMarginForAxis(axis, ownerWidth))
72
+ if mode in (SizingMode.StretchFit, SizingMode.FitContent):
73
+ size = size if maxSize.isUndefined() or size < maxSize.unwrap() else maxSize.unwrap()
74
+ elif mode == SizingMode.MaxContent and maxSize.isDefined():
75
+ mode = SizingMode.FitContent
76
+ size = maxSize.unwrap()
77
+ return mode, size
78
+
79
+
80
+ def computeFlexBasisForChild(
81
+ node: Node,
82
+ child: Node,
83
+ width: float,
84
+ widthMode: SizingMode,
85
+ height: float,
86
+ ownerWidth: float,
87
+ ownerHeight: float,
88
+ heightMode: SizingMode,
89
+ direction: YGDirection,
90
+ layoutMarkerData: LayoutData,
91
+ depth: int,
92
+ generationCount: int,
93
+ ) -> None:
94
+ mainAxis = resolveDirection(node.style().flexDirection(), direction)
95
+ isMainAxisRow = isRow(mainAxis)
96
+ mainAxisSize = width if isMainAxisRow else height
97
+ mainAxisOwnerSize = ownerWidth if isMainAxisRow else ownerHeight
98
+ childWidth = float("nan")
99
+ childHeight = float("nan")
100
+ resolvedFlexBasis = child.resolveFlexBasis(direction, mainAxis, mainAxisOwnerSize, ownerWidth)
101
+ isRowStyleDimDefined = child.hasDefiniteLength(YGDimension.YGDimensionWidth, ownerWidth)
102
+ isColumnStyleDimDefined = child.hasDefiniteLength(YGDimension.YGDimensionHeight, ownerHeight)
103
+
104
+ if resolvedFlexBasis.isDefined() and isDefined(mainAxisSize):
105
+ if child.getLayout().computedFlexBasis.isUndefined() or (
106
+ child.getConfig().isExperimentalFeatureEnabled(YGExperimentalFeature.YGExperimentalFeatureWebFlexBasis)
107
+ and child.getLayout().computedFlexBasisGeneration != generationCount
108
+ ):
109
+ paddingAndBorder = FloatOptional(paddingAndBorderForAxis(child, mainAxis, direction, ownerWidth))
110
+ child.setLayoutComputedFlexBasis(
111
+ maxOrDefinedFloatOptional(resolvedFlexBasis, paddingAndBorder)
112
+ )
113
+ elif isMainAxisRow and isRowStyleDimDefined:
114
+ # The width is definite, so use that as the flex basis.
115
+ paddingAndBorder = FloatOptional(paddingAndBorderForAxis(child, YGFlexDirection.YGFlexDirectionRow, direction, ownerWidth))
116
+ child.setLayoutComputedFlexBasis(
117
+ FloatOptional(
118
+ maxOrDefined(
119
+ child.getResolvedDimension(direction, YGDimension.YGDimensionWidth, ownerWidth, ownerWidth).unwrap(),
120
+ paddingAndBorder.unwrap(),
121
+ )
122
+ )
123
+ )
124
+ elif (not isMainAxisRow) and isColumnStyleDimDefined:
125
+ # The height is definite, so use that as the flex basis.
126
+ paddingAndBorder = FloatOptional(paddingAndBorderForAxis(child, YGFlexDirection.YGFlexDirectionColumn, direction, ownerWidth))
127
+ child.setLayoutComputedFlexBasis(
128
+ FloatOptional(
129
+ maxOrDefined(
130
+ child.getResolvedDimension(direction, YGDimension.YGDimensionHeight, ownerHeight, ownerWidth).unwrap(),
131
+ paddingAndBorder.unwrap(),
132
+ )
133
+ )
134
+ )
135
+ else:
136
+ # Compute the flex basis and hypothetical main size (i.e. the clamped flex
137
+ # basis).
138
+ childWidthSizingMode = SizingMode.MaxContent
139
+ childHeightSizingMode = SizingMode.MaxContent
140
+ marginRow = child.style().computeMarginForAxis(YGFlexDirection.YGFlexDirectionRow, ownerWidth)
141
+ marginColumn = child.style().computeMarginForAxis(YGFlexDirection.YGFlexDirectionColumn, ownerWidth)
142
+ if isRowStyleDimDefined:
143
+ childWidth = child.getResolvedDimension(direction, YGDimension.YGDimensionWidth, ownerWidth, ownerWidth).unwrap() + marginRow
144
+ childWidthSizingMode = SizingMode.StretchFit
145
+ if isColumnStyleDimDefined:
146
+ childHeight = child.getResolvedDimension(direction, YGDimension.YGDimensionHeight, ownerHeight, ownerWidth).unwrap() + marginColumn
147
+ childHeightSizingMode = SizingMode.StretchFit
148
+ # The W3C spec doesn't say anything about the 'overflow' property, but all
149
+ # major browsers appear to implement the following logic.
150
+ if ((not isMainAxisRow) and node.style().overflow() == YGOverflow.YGOverflowScroll) or (
151
+ node.style().overflow() != YGOverflow.YGOverflowScroll
152
+ ):
153
+ if isUndefined(childWidth) and isDefined(width):
154
+ childWidth = width
155
+ childWidthSizingMode = SizingMode.FitContent
156
+ if (isMainAxisRow and node.style().overflow() == YGOverflow.YGOverflowScroll) or (
157
+ node.style().overflow() != YGOverflow.YGOverflowScroll
158
+ ):
159
+ if isUndefined(childHeight) and isDefined(height):
160
+ childHeight = height
161
+ childHeightSizingMode = SizingMode.FitContent
162
+ childStyle = child.style()
163
+ if childStyle.aspectRatio().isDefined():
164
+ if (not isMainAxisRow) and childWidthSizingMode == SizingMode.StretchFit:
165
+ childHeight = marginColumn + (childWidth - marginRow) / childStyle.aspectRatio().unwrap()
166
+ childHeightSizingMode = SizingMode.StretchFit
167
+ elif isMainAxisRow and childHeightSizingMode == SizingMode.StretchFit:
168
+ childWidth = marginRow + (childHeight - marginColumn) * childStyle.aspectRatio().unwrap()
169
+ childWidthSizingMode = SizingMode.StretchFit
170
+ # If child has no defined size in the cross axis and is set to stretch, set
171
+ # the cross axis to be measured exactly with the available inner width
172
+ hasExactWidth = isDefined(width) and widthMode == SizingMode.StretchFit
173
+ childWidthStretch = resolveChildAlignment(node, child) == YGAlign.YGAlignStretch and childWidthSizingMode != SizingMode.StretchFit
174
+ if (not isMainAxisRow) and (not isRowStyleDimDefined) and hasExactWidth and childWidthStretch:
175
+ childWidth = width
176
+ childWidthSizingMode = SizingMode.StretchFit
177
+ if childStyle.aspectRatio().isDefined():
178
+ childHeight = (childWidth - marginRow) / childStyle.aspectRatio().unwrap()
179
+ childHeightSizingMode = SizingMode.StretchFit
180
+ hasExactHeight = isDefined(height) and heightMode == SizingMode.StretchFit
181
+ childHeightStretch = resolveChildAlignment(node, child) == YGAlign.YGAlignStretch and childHeightSizingMode != SizingMode.StretchFit
182
+ if isMainAxisRow and (not isColumnStyleDimDefined) and hasExactHeight and childHeightStretch:
183
+ childHeight = height
184
+ childHeightSizingMode = SizingMode.StretchFit
185
+ if childStyle.aspectRatio().isDefined():
186
+ childWidth = (childHeight - marginColumn) * childStyle.aspectRatio().unwrap()
187
+ childWidthSizingMode = SizingMode.StretchFit
188
+ childWidthSizingMode, childWidth = constrainMaxSizeForMode(
189
+ child, direction, YGFlexDirection.YGFlexDirectionRow, ownerWidth, ownerWidth, childWidthSizingMode, childWidth
190
+ )
191
+ childHeightSizingMode, childHeight = constrainMaxSizeForMode(
192
+ child, direction, YGFlexDirection.YGFlexDirectionColumn, ownerHeight, ownerWidth, childHeightSizingMode, childHeight
193
+ )
194
+ # Measure the child
195
+ calculateLayoutInternal(
196
+ child,
197
+ childWidth,
198
+ childHeight,
199
+ direction,
200
+ childWidthSizingMode,
201
+ childHeightSizingMode,
202
+ ownerWidth,
203
+ ownerHeight,
204
+ False,
205
+ LayoutPassReason.kMeasureChild,
206
+ layoutMarkerData,
207
+ depth,
208
+ generationCount,
209
+ )
210
+ child.setLayoutComputedFlexBasis(
211
+ FloatOptional(
212
+ maxOrDefined(
213
+ child.getLayout().measuredDimension(
214
+ YGDimension.YGDimensionWidth if isMainAxisRow else YGDimension.YGDimensionHeight
215
+ ),
216
+ paddingAndBorderForAxis(child, mainAxis, direction, ownerWidth),
217
+ )
218
+ )
219
+ )
220
+ child.setLayoutComputedFlexBasisGeneration(generationCount)
221
+
222
+
223
+ def measureNodeWithMeasureFunc(
224
+ node: Node,
225
+ direction: YGDirection,
226
+ availableWidth: float,
227
+ availableHeight: float,
228
+ widthSizingMode: SizingMode,
229
+ heightSizingMode: SizingMode,
230
+ ownerWidth: float,
231
+ ownerHeight: float,
232
+ layoutMarkerData: LayoutData,
233
+ reason: LayoutPassReason,
234
+ ) -> None:
235
+ if widthSizingMode == SizingMode.MaxContent:
236
+ availableWidth = float("nan")
237
+ if heightSizingMode == SizingMode.MaxContent:
238
+ availableHeight = float("nan")
239
+ layout = node.getLayout()
240
+ paddingAndBorderAxisRow = (
241
+ layout.padding(YGEdge.YGEdgeLeft)
242
+ + layout.padding(YGEdge.YGEdgeRight)
243
+ + layout.border(YGEdge.YGEdgeLeft)
244
+ + layout.border(YGEdge.YGEdgeRight)
245
+ )
246
+ paddingAndBorderAxisColumn = (
247
+ layout.padding(YGEdge.YGEdgeTop)
248
+ + layout.padding(YGEdge.YGEdgeBottom)
249
+ + layout.border(YGEdge.YGEdgeTop)
250
+ + layout.border(YGEdge.YGEdgeBottom)
251
+ )
252
+ innerWidth = availableWidth if isnan(availableWidth) else maxOrDefined(0.0, availableWidth - paddingAndBorderAxisRow)
253
+ innerHeight = availableHeight if isnan(availableHeight) else maxOrDefined(0.0, availableHeight - paddingAndBorderAxisColumn)
254
+ if widthSizingMode == SizingMode.StretchFit and heightSizingMode == SizingMode.StretchFit:
255
+ node.setLayoutMeasuredDimension(boundAxis(node, YGFlexDirection.YGFlexDirectionRow, direction, availableWidth, ownerWidth, ownerWidth), YGDimension.YGDimensionWidth)
256
+ node.setLayoutMeasuredDimension(boundAxis(node, YGFlexDirection.YGFlexDirectionColumn, direction, availableHeight, ownerHeight, ownerWidth), YGDimension.YGDimensionHeight)
257
+ else:
258
+ Event.publish(node, Event.MeasureCallbackStart, EventData())
259
+ measuredSize = node.measure(innerWidth, YGMeasureMode.YGMeasureModeExactly if widthSizingMode == SizingMode.StretchFit else (YGMeasureMode.YGMeasureModeAtMost if widthSizingMode == SizingMode.FitContent else YGMeasureMode.YGMeasureModeUndefined), innerHeight, YGMeasureMode.YGMeasureModeExactly if heightSizingMode == SizingMode.StretchFit else (YGMeasureMode.YGMeasureModeAtMost if heightSizingMode == SizingMode.FitContent else YGMeasureMode.YGMeasureModeUndefined))
260
+ layoutMarkerData.measureCallbacks += 1
261
+ layoutMarkerData.measureCallbackReasonsCount[int(reason)] += 1
262
+ Event.publish(
263
+ node,
264
+ Event.MeasureCallbackEnd,
265
+ MeasureCallbackEndData(
266
+ width=innerWidth,
267
+ widthMeasureMode=YGMeasureMode.YGMeasureModeExactly if widthSizingMode == SizingMode.StretchFit else (YGMeasureMode.YGMeasureModeAtMost if widthSizingMode == SizingMode.FitContent else YGMeasureMode.YGMeasureModeUndefined),
268
+ height=innerHeight,
269
+ heightMeasureMode=YGMeasureMode.YGMeasureModeExactly if heightSizingMode == SizingMode.StretchFit else (YGMeasureMode.YGMeasureModeAtMost if heightSizingMode == SizingMode.FitContent else YGMeasureMode.YGMeasureModeUndefined),
270
+ measuredWidth=measuredSize.width,
271
+ measuredHeight=measuredSize.height,
272
+ reason=reason,
273
+ ),
274
+ )
275
+ node.setLayoutMeasuredDimension(
276
+ boundAxis(
277
+ node,
278
+ YGFlexDirection.YGFlexDirectionRow,
279
+ direction,
280
+ measuredSize.width + paddingAndBorderAxisRow if widthSizingMode in (SizingMode.MaxContent, SizingMode.FitContent) else availableWidth,
281
+ ownerWidth,
282
+ ownerWidth,
283
+ ),
284
+ YGDimension.YGDimensionWidth,
285
+ )
286
+ node.setLayoutMeasuredDimension(
287
+ boundAxis(
288
+ node,
289
+ YGFlexDirection.YGFlexDirectionColumn,
290
+ direction,
291
+ measuredSize.height + paddingAndBorderAxisColumn if heightSizingMode in (SizingMode.MaxContent, SizingMode.FitContent) else availableHeight,
292
+ ownerHeight,
293
+ ownerWidth,
294
+ ),
295
+ YGDimension.YGDimensionHeight,
296
+ )
297
+
298
+
299
+ def measureNodeWithoutChildren(
300
+ node: Node,
301
+ direction: YGDirection,
302
+ availableWidth: float,
303
+ availableHeight: float,
304
+ widthSizingMode: SizingMode,
305
+ heightSizingMode: SizingMode,
306
+ ownerWidth: float,
307
+ ownerHeight: float,
308
+ ) -> None:
309
+ layout = node.getLayout()
310
+ width = availableWidth
311
+ if widthSizingMode in (SizingMode.MaxContent, SizingMode.FitContent):
312
+ width = layout.padding(YGEdge.YGEdgeLeft) + layout.padding(YGEdge.YGEdgeRight) + layout.border(YGEdge.YGEdgeLeft) + layout.border(YGEdge.YGEdgeRight)
313
+ node.setLayoutMeasuredDimension(boundAxis(node, YGFlexDirection.YGFlexDirectionRow, direction, width, ownerWidth, ownerWidth), YGDimension.YGDimensionWidth)
314
+ height = availableHeight
315
+ if heightSizingMode in (SizingMode.MaxContent, SizingMode.FitContent):
316
+ height = layout.padding(YGEdge.YGEdgeTop) + layout.padding(YGEdge.YGEdgeBottom) + layout.border(YGEdge.YGEdgeTop) + layout.border(YGEdge.YGEdgeBottom)
317
+ node.setLayoutMeasuredDimension(boundAxis(node, YGFlexDirection.YGFlexDirectionColumn, direction, height, ownerHeight, ownerWidth), YGDimension.YGDimensionHeight)
318
+
319
+
320
+ def isFixedSize(dim: float, sizingMode: SizingMode) -> bool:
321
+ return sizingMode == SizingMode.StretchFit or (dim == dim and sizingMode == SizingMode.FitContent and dim <= 0.0)
322
+
323
+
324
+ def measureNodeWithFixedSize(
325
+ node: Node,
326
+ direction: YGDirection,
327
+ availableWidth: float,
328
+ availableHeight: float,
329
+ widthSizingMode: SizingMode,
330
+ heightSizingMode: SizingMode,
331
+ ownerWidth: float,
332
+ ownerHeight: float,
333
+ ) -> bool:
334
+ if isFixedSize(availableWidth, widthSizingMode) and isFixedSize(availableHeight, heightSizingMode):
335
+ node.setLayoutMeasuredDimension(boundAxis(node, YGFlexDirection.YGFlexDirectionRow, direction, 0.0 if isnan(availableWidth) or (widthSizingMode == SizingMode.FitContent and availableWidth < 0.0) else availableWidth, ownerWidth, ownerWidth), YGDimension.YGDimensionWidth)
336
+ node.setLayoutMeasuredDimension(boundAxis(node, YGFlexDirection.YGFlexDirectionColumn, direction, 0.0 if isnan(availableHeight) or (heightSizingMode == SizingMode.FitContent and availableHeight < 0.0) else availableHeight, ownerHeight, ownerWidth), YGDimension.YGDimensionHeight)
337
+ return True
338
+ return False
339
+
340
+
341
+ def zeroOutLayoutRecursively(node: Node) -> None:
342
+ node.setLayout(LayoutResults())
343
+ node.setLayoutDimension(0, YGDimension.YGDimensionWidth)
344
+ node.setLayoutDimension(0, YGDimension.YGDimensionHeight)
345
+ node.setHasNewLayout(True)
346
+ node.cloneChildrenIfNeeded()
347
+ for child in node.getChildren():
348
+ zeroOutLayoutRecursively(child)
349
+
350
+
351
+ def cleanupContentsNodesRecursively(node: Node) -> None:
352
+ if node.hasContentsChildren():
353
+ node.cloneContentsChildrenIfNeeded()
354
+ for child in node.getChildren():
355
+ if child.style().display().name.endswith("Contents"):
356
+ child.setLayout(LayoutResults())
357
+ child.setLayoutDimension(0, YGDimension.YGDimensionWidth)
358
+ child.setLayoutDimension(0, YGDimension.YGDimensionHeight)
359
+ child.setHasNewLayout(True)
360
+ child.setDirty(False)
361
+ child.cloneChildrenIfNeeded()
362
+ cleanupContentsNodesRecursively(child)
363
+
364
+
365
+ def calculateAvailableInnerDimension(
366
+ node: Node,
367
+ direction: YGDirection,
368
+ dimensionValue: YGDimension,
369
+ availableDim: float,
370
+ paddingAndBorder: float,
371
+ ownerDim: float,
372
+ ownerWidth: float,
373
+ ) -> float:
374
+ availableInnerDim = availableDim - paddingAndBorder
375
+ if availableInnerDim == availableInnerDim:
376
+ minDimensionOptional = node.style().resolvedMinDimension(direction, dimensionValue, ownerDim, ownerWidth)
377
+ minInnerDim = 0.0 if minDimensionOptional.isUndefined() else minDimensionOptional.unwrap() - paddingAndBorder
378
+ maxDimensionOptional = node.style().resolvedMaxDimension(direction, dimensionValue, ownerDim, ownerWidth)
379
+ maxInnerDim = float("inf") if maxDimensionOptional.isUndefined() else maxDimensionOptional.unwrap() - paddingAndBorder
380
+ availableInnerDim = maxOrDefined(min(availableInnerDim, maxInnerDim), minInnerDim)
381
+ return availableInnerDim
382
+
383
+
384
+ def computeFlexBasisForChildren(
385
+ node: Node,
386
+ availableInnerWidth: float,
387
+ availableInnerHeight: float,
388
+ widthSizingMode: SizingMode,
389
+ heightSizingMode: SizingMode,
390
+ direction: YGDirection,
391
+ mainAxis: YGFlexDirection,
392
+ performLayout: bool,
393
+ layoutMarkerData: LayoutData,
394
+ depth: int,
395
+ generationCount: int,
396
+ ) -> float:
397
+ totalOuterFlexBasis = float32(0.0)
398
+ singleFlexChild = None
399
+ children = list(node.getLayoutChildren())
400
+ sizingModeMainDim = widthSizingMode if isRow(mainAxis) else heightSizingMode
401
+ if sizingModeMainDim == SizingMode.StretchFit:
402
+ for child in children:
403
+ if child.isNodeFlexible():
404
+ if singleFlexChild is not None or child.resolveFlexGrow() == 0.0 or child.resolveFlexShrink() == 0.0:
405
+ singleFlexChild = None
406
+ break
407
+ singleFlexChild = child
408
+ for child in children:
409
+ child.processDimensions()
410
+ if child.style().display().name.endswith("None"):
411
+ zeroOutLayoutRecursively(child)
412
+ child.setHasNewLayout(True)
413
+ child.setDirty(False)
414
+ continue
415
+ if performLayout:
416
+ childDirection = child.resolveDirection(direction)
417
+ child.setPosition(childDirection, availableInnerWidth, availableInnerHeight)
418
+ if child.style().positionType().name.endswith("Absolute"):
419
+ continue
420
+ if child == singleFlexChild:
421
+ child.setLayoutComputedFlexBasisGeneration(generationCount)
422
+ child.setLayoutComputedFlexBasis(FloatOptional(0.0))
423
+ else:
424
+ computeFlexBasisForChild(
425
+ node,
426
+ child,
427
+ availableInnerWidth,
428
+ widthSizingMode,
429
+ availableInnerHeight,
430
+ availableInnerWidth,
431
+ availableInnerHeight,
432
+ heightSizingMode,
433
+ direction,
434
+ layoutMarkerData,
435
+ depth,
436
+ generationCount,
437
+ )
438
+ totalOuterFlexBasis = float32(
439
+ totalOuterFlexBasis
440
+ + float32(
441
+ child.getLayout().computedFlexBasis.unwrap()
442
+ + child.style().computeMarginForAxis(mainAxis, availableInnerWidth)
443
+ )
444
+ )
445
+ return totalOuterFlexBasis
446
+
447
+
448
+ def distributeFreeSpaceFirstPass(
449
+ flexLine,
450
+ direction: YGDirection,
451
+ mainAxis: YGFlexDirection,
452
+ ownerWidth: float,
453
+ mainAxisOwnerSize: float,
454
+ availableInnerMainDim: float,
455
+ availableInnerWidth: float,
456
+ ) -> None:
457
+ deltaFreeSpace = float32(0.0)
458
+ for currentLineChild in flexLine.itemsInFlow:
459
+ childFlexBasis = float32(
460
+ boundAxisWithinMinAndMax(
461
+ currentLineChild,
462
+ direction,
463
+ mainAxis,
464
+ currentLineChild.getLayout().computedFlexBasis,
465
+ mainAxisOwnerSize,
466
+ ownerWidth,
467
+ ).unwrap()
468
+ )
469
+ if flexLine.layout.remainingFreeSpace < 0:
470
+ flexShrinkScaledFactor = float32(
471
+ -currentLineChild.resolveFlexShrink() * childFlexBasis
472
+ )
473
+ if flexShrinkScaledFactor == flexShrinkScaledFactor and flexShrinkScaledFactor != 0:
474
+ shrinkRatio = float32(
475
+ floatDivision(
476
+ flexLine.layout.remainingFreeSpace,
477
+ flexLine.layout.totalFlexShrinkScaledFactors,
478
+ )
479
+ )
480
+ baseMainSize = float32(
481
+ childFlexBasis
482
+ + float32(shrinkRatio * flexShrinkScaledFactor)
483
+ )
484
+ boundMainSize = boundAxis(currentLineChild, mainAxis, direction, baseMainSize, availableInnerMainDim, availableInnerWidth)
485
+ if baseMainSize == baseMainSize and boundMainSize == boundMainSize and baseMainSize != boundMainSize:
486
+ deltaFreeSpace = float32(
487
+ deltaFreeSpace + float32(boundMainSize - childFlexBasis)
488
+ )
489
+ flexLine.layout.totalFlexShrinkScaledFactors = float32(
490
+ flexLine.layout.totalFlexShrinkScaledFactors
491
+ - float32(
492
+ -currentLineChild.resolveFlexShrink()
493
+ * currentLineChild.getLayout().computedFlexBasis.unwrap()
494
+ )
495
+ )
496
+ elif flexLine.layout.remainingFreeSpace == flexLine.layout.remainingFreeSpace and flexLine.layout.remainingFreeSpace > 0:
497
+ flexGrowFactor = currentLineChild.resolveFlexGrow()
498
+ if flexGrowFactor == flexGrowFactor and flexGrowFactor != 0:
499
+ growRatio = float32(
500
+ floatDivision(
501
+ flexLine.layout.remainingFreeSpace,
502
+ flexLine.layout.totalFlexGrowFactors,
503
+ )
504
+ )
505
+ baseMainSize = float32(
506
+ childFlexBasis
507
+ + float32(growRatio * flexGrowFactor)
508
+ )
509
+ boundMainSize = boundAxis(currentLineChild, mainAxis, direction, baseMainSize, availableInnerMainDim, availableInnerWidth)
510
+ if baseMainSize == baseMainSize and boundMainSize == boundMainSize and baseMainSize != boundMainSize:
511
+ deltaFreeSpace = float32(
512
+ deltaFreeSpace + float32(boundMainSize - childFlexBasis)
513
+ )
514
+ flexLine.layout.totalFlexGrowFactors = float32(
515
+ flexLine.layout.totalFlexGrowFactors - flexGrowFactor
516
+ )
517
+ flexLine.layout.remainingFreeSpace = float32(
518
+ flexLine.layout.remainingFreeSpace - deltaFreeSpace
519
+ )
520
+
521
+
522
+ def distributeFreeSpaceSecondPass(
523
+ flexLine,
524
+ node: Node,
525
+ mainAxis: YGFlexDirection,
526
+ crossAxis: YGFlexDirection,
527
+ direction: YGDirection,
528
+ ownerWidth: float,
529
+ mainAxisOwnerSize: float,
530
+ availableInnerMainDim: float,
531
+ availableInnerCrossDim: float,
532
+ availableInnerWidth: float,
533
+ availableInnerHeight: float,
534
+ mainAxisOverflows: bool,
535
+ sizingModeCrossDim: SizingMode,
536
+ performLayout: bool,
537
+ layoutMarkerData: LayoutData,
538
+ depth: int,
539
+ generationCount: int,
540
+ ) -> float:
541
+ deltaFreeSpace = float32(0.0)
542
+ isMainAxisRow = isRow(mainAxis)
543
+ isNodeFlexWrap = node.style().flexWrap() != getattr(node.style().flexWrap().__class__, "YGWrapNoWrap", node.style().flexWrap())
544
+ for currentLineChild in flexLine.itemsInFlow:
545
+ childFlexBasis = float32(
546
+ boundAxisWithinMinAndMax(
547
+ currentLineChild,
548
+ direction,
549
+ mainAxis,
550
+ currentLineChild.getLayout().computedFlexBasis,
551
+ mainAxisOwnerSize,
552
+ ownerWidth,
553
+ ).unwrap()
554
+ )
555
+ updatedMainSize = childFlexBasis
556
+ if flexLine.layout.remainingFreeSpace == flexLine.layout.remainingFreeSpace and flexLine.layout.remainingFreeSpace < 0:
557
+ flexShrinkScaledFactor = float32(
558
+ -currentLineChild.resolveFlexShrink() * childFlexBasis
559
+ )
560
+ if flexShrinkScaledFactor != 0:
561
+ if flexLine.layout.totalFlexShrinkScaledFactors == 0:
562
+ childSize = float32(childFlexBasis + flexShrinkScaledFactor)
563
+ else:
564
+ shrinkRatio = float32(
565
+ floatDivision(
566
+ flexLine.layout.remainingFreeSpace,
567
+ flexLine.layout.totalFlexShrinkScaledFactors,
568
+ )
569
+ )
570
+ childSize = float32(
571
+ childFlexBasis
572
+ + float32(shrinkRatio * flexShrinkScaledFactor)
573
+ )
574
+ updatedMainSize = float32(
575
+ boundAxis(
576
+ currentLineChild,
577
+ mainAxis,
578
+ direction,
579
+ childSize,
580
+ availableInnerMainDim,
581
+ availableInnerWidth,
582
+ )
583
+ )
584
+ elif flexLine.layout.remainingFreeSpace == flexLine.layout.remainingFreeSpace and flexLine.layout.remainingFreeSpace > 0:
585
+ flexGrowFactor = currentLineChild.resolveFlexGrow()
586
+ if flexGrowFactor == flexGrowFactor and flexGrowFactor != 0:
587
+ growRatio = float32(
588
+ floatDivision(
589
+ flexLine.layout.remainingFreeSpace,
590
+ flexLine.layout.totalFlexGrowFactors,
591
+ )
592
+ )
593
+ updatedMainSize = float32(
594
+ boundAxis(
595
+ currentLineChild,
596
+ mainAxis,
597
+ direction,
598
+ float32(
599
+ childFlexBasis
600
+ + float32(growRatio * flexGrowFactor)
601
+ ),
602
+ availableInnerMainDim,
603
+ availableInnerWidth,
604
+ )
605
+ )
606
+ deltaFreeSpace = float32(
607
+ deltaFreeSpace + float32(updatedMainSize - childFlexBasis)
608
+ )
609
+ marginMain = currentLineChild.style().computeMarginForAxis(mainAxis, availableInnerWidth)
610
+ marginCross = currentLineChild.style().computeMarginForAxis(crossAxis, availableInnerWidth)
611
+ childCrossSize = float("nan")
612
+ childMainSize = updatedMainSize + marginMain
613
+ childStyle = currentLineChild.style()
614
+ childMainSizingMode = SizingMode.StretchFit
615
+ if childStyle.aspectRatio().isDefined():
616
+ childCrossSize = (
617
+ (childMainSize - marginMain) / childStyle.aspectRatio().unwrap()
618
+ if isMainAxisRow
619
+ else (childMainSize - marginMain) * childStyle.aspectRatio().unwrap()
620
+ )
621
+ childCrossSizingMode = SizingMode.StretchFit
622
+ childCrossSize += marginCross
623
+ elif (
624
+ availableInnerCrossDim == availableInnerCrossDim
625
+ and not currentLineChild.hasDefiniteLength(
626
+ YGDimension.YGDimensionHeight if isMainAxisRow else YGDimension.YGDimensionWidth,
627
+ availableInnerCrossDim,
628
+ )
629
+ and sizingModeCrossDim == SizingMode.StretchFit
630
+ and not (isNodeFlexWrap and mainAxisOverflows)
631
+ and resolveChildAlignment(node, currentLineChild) == YGAlign.YGAlignStretch
632
+ and not currentLineChild.style().flexStartMarginIsAuto(crossAxis, direction)
633
+ and not currentLineChild.style().flexEndMarginIsAuto(crossAxis, direction)
634
+ ):
635
+ childCrossSize = availableInnerCrossDim
636
+ childCrossSizingMode = SizingMode.StretchFit
637
+ elif not currentLineChild.hasDefiniteLength(
638
+ YGDimension.YGDimensionHeight if isMainAxisRow else YGDimension.YGDimensionWidth,
639
+ availableInnerCrossDim,
640
+ ):
641
+ childCrossSize = availableInnerCrossDim
642
+ childCrossSizingMode = SizingMode.MaxContent if isnan(childCrossSize) else SizingMode.FitContent
643
+ else:
644
+ childCrossSize = currentLineChild.getResolvedDimension(
645
+ direction,
646
+ YGDimension.YGDimensionHeight if isMainAxisRow else YGDimension.YGDimensionWidth,
647
+ availableInnerCrossDim,
648
+ availableInnerWidth,
649
+ ).unwrap() + marginCross
650
+ isLoosePercentageMeasurement = (
651
+ currentLineChild.getProcessedDimension(
652
+ YGDimension.YGDimensionHeight if isMainAxisRow else YGDimension.YGDimensionWidth
653
+ ).isPercent()
654
+ and sizingModeCrossDim != SizingMode.StretchFit
655
+ )
656
+ childCrossSizingMode = (
657
+ SizingMode.MaxContent
658
+ if isnan(childCrossSize) or isLoosePercentageMeasurement
659
+ else SizingMode.StretchFit
660
+ )
661
+ childMainSizingMode, childMainSize = constrainMaxSizeForMode(currentLineChild, direction, mainAxis, availableInnerMainDim, availableInnerWidth, childMainSizingMode, childMainSize)
662
+ childCrossSizingMode, childCrossSize = constrainMaxSizeForMode(currentLineChild, direction, crossAxis, availableInnerCrossDim, availableInnerWidth, childCrossSizingMode, childCrossSize)
663
+ requiresStretchLayout = (
664
+ not currentLineChild.hasDefiniteLength(YGDimension.YGDimensionHeight if isMainAxisRow else YGDimension.YGDimensionWidth, availableInnerCrossDim)
665
+ and resolveChildAlignment(node, currentLineChild) == YGAlign.YGAlignStretch
666
+ and not currentLineChild.style().flexStartMarginIsAuto(crossAxis, direction)
667
+ and not currentLineChild.style().flexEndMarginIsAuto(crossAxis, direction)
668
+ )
669
+ childWidth = childMainSize if isMainAxisRow else childCrossSize
670
+ childHeight = childMainSize if not isMainAxisRow else childCrossSize
671
+ childWidthSizingMode = childMainSizingMode if isMainAxisRow else childCrossSizingMode
672
+ childHeightSizingMode = childMainSizingMode if not isMainAxisRow else childCrossSizingMode
673
+ isLayoutPass = performLayout and not requiresStretchLayout
674
+ calculateLayoutInternal(
675
+ currentLineChild,
676
+ childWidth,
677
+ childHeight,
678
+ node.getLayout().direction(),
679
+ childWidthSizingMode,
680
+ childHeightSizingMode,
681
+ availableInnerWidth,
682
+ availableInnerHeight,
683
+ isLayoutPass,
684
+ LayoutPassReason.kFlexLayout if isLayoutPass else LayoutPassReason.kFlexMeasure,
685
+ layoutMarkerData,
686
+ depth,
687
+ generationCount,
688
+ )
689
+ node.setLayoutHadOverflow(node.getLayout().hadOverflow() or currentLineChild.getLayout().hadOverflow())
690
+ return deltaFreeSpace
691
+
692
+
693
+ def resolveFlexibleLength(
694
+ node: Node,
695
+ flexLine,
696
+ mainAxis: YGFlexDirection,
697
+ crossAxis: YGFlexDirection,
698
+ direction: YGDirection,
699
+ ownerWidth: float,
700
+ mainAxisOwnerSize: float,
701
+ availableInnerMainDim: float,
702
+ availableInnerCrossDim: float,
703
+ availableInnerWidth: float,
704
+ availableInnerHeight: float,
705
+ mainAxisOverflows: bool,
706
+ sizingModeCrossDim: SizingMode,
707
+ performLayout: bool,
708
+ layoutMarkerData: LayoutData,
709
+ depth: int,
710
+ generationCount: int,
711
+ ) -> None:
712
+ originalFreeSpace = flexLine.layout.remainingFreeSpace
713
+ distributeFreeSpaceFirstPass(
714
+ flexLine,
715
+ direction,
716
+ mainAxis,
717
+ ownerWidth,
718
+ mainAxisOwnerSize,
719
+ availableInnerMainDim,
720
+ availableInnerWidth,
721
+ )
722
+ distributedFreeSpace = distributeFreeSpaceSecondPass(
723
+ flexLine,
724
+ node,
725
+ mainAxis,
726
+ crossAxis,
727
+ direction,
728
+ ownerWidth,
729
+ mainAxisOwnerSize,
730
+ availableInnerMainDim,
731
+ availableInnerCrossDim,
732
+ availableInnerWidth,
733
+ availableInnerHeight,
734
+ mainAxisOverflows,
735
+ sizingModeCrossDim,
736
+ performLayout,
737
+ layoutMarkerData,
738
+ depth,
739
+ generationCount,
740
+ )
741
+ flexLine.layout.remainingFreeSpace = float32(
742
+ originalFreeSpace - distributedFreeSpace
743
+ )
744
+
745
+
746
+ def justifyMainAxis(
747
+ node: Node,
748
+ flexLine,
749
+ mainAxis: YGFlexDirection,
750
+ crossAxis: YGFlexDirection,
751
+ direction: YGDirection,
752
+ sizingModeMainDim: SizingMode,
753
+ sizingModeCrossDim: SizingMode,
754
+ mainAxisOwnerSize: float,
755
+ ownerWidth: float,
756
+ availableInnerMainDim: float,
757
+ availableInnerCrossDim: float,
758
+ availableInnerWidth: float,
759
+ performLayout: bool,
760
+ ) -> None:
761
+ style = node.style()
762
+ leadingPaddingAndBorderMain = style.computeFlexStartPaddingAndBorder(mainAxis, direction, ownerWidth)
763
+ trailingPaddingAndBorderMain = style.computeFlexEndPaddingAndBorder(mainAxis, direction, ownerWidth)
764
+ gap = style.computeGapForAxis(mainAxis, availableInnerMainDim)
765
+ if sizingModeMainDim == SizingMode.FitContent and flexLine.layout.remainingFreeSpace > 0:
766
+ if style.minDimension(dimension(mainAxis)).isDefined() and style.resolvedMinDimension(
767
+ direction, dimension(mainAxis), mainAxisOwnerSize, ownerWidth
768
+ ).isDefined():
769
+ minAvailableMainDim = (
770
+ style.resolvedMinDimension(direction, dimension(mainAxis), mainAxisOwnerSize, ownerWidth).unwrap()
771
+ - leadingPaddingAndBorderMain
772
+ - trailingPaddingAndBorderMain
773
+ )
774
+ occupiedSpaceByChildNodes = availableInnerMainDim - flexLine.layout.remainingFreeSpace
775
+ flexLine.layout.remainingFreeSpace = maxOrDefined(0.0, minAvailableMainDim - occupiedSpaceByChildNodes)
776
+ else:
777
+ flexLine.layout.remainingFreeSpace = 0.0
778
+ leadingMainDim = 0.0
779
+ betweenMainDim = gap
780
+ justifyContent = (
781
+ node.style().justifyContent()
782
+ if flexLine.layout.remainingFreeSpace >= 0
783
+ else fallbackAlignment(node.style().justifyContent())
784
+ )
785
+ if flexLine.numberOfAutoMargins == 0:
786
+ if justifyContent == YGJustify.YGJustifyCenter:
787
+ leadingMainDim = flexLine.layout.remainingFreeSpace / 2
788
+ elif justifyContent == YGJustify.YGJustifyFlexEnd:
789
+ leadingMainDim = flexLine.layout.remainingFreeSpace
790
+ elif justifyContent == YGJustify.YGJustifySpaceBetween:
791
+ if len(flexLine.itemsInFlow) > 1:
792
+ betweenMainDim += flexLine.layout.remainingFreeSpace / float(len(flexLine.itemsInFlow) - 1)
793
+ elif justifyContent == YGJustify.YGJustifySpaceEvenly:
794
+ leadingMainDim = floatDivision(
795
+ flexLine.layout.remainingFreeSpace,
796
+ float(len(flexLine.itemsInFlow) + 1),
797
+ )
798
+ betweenMainDim += leadingMainDim
799
+ elif justifyContent == YGJustify.YGJustifySpaceAround:
800
+ leadingMainDim = 0.5 * floatDivision(
801
+ flexLine.layout.remainingFreeSpace,
802
+ float(len(flexLine.itemsInFlow)),
803
+ )
804
+ betweenMainDim += leadingMainDim * 2
805
+ flexLine.layout.mainDim = leadingPaddingAndBorderMain + leadingMainDim
806
+ flexLine.layout.crossDim = 0.0
807
+ maxAscentForCurrentLine = 0.0
808
+ maxDescentForCurrentLine = 0.0
809
+ nodeBaselineLayout = isBaselineLayout(node)
810
+ for child in flexLine.itemsInFlow:
811
+ childLayout = child.getLayout()
812
+ if child.style().flexStartMarginIsAuto(mainAxis, direction) and flexLine.layout.remainingFreeSpace > 0.0:
813
+ flexLine.layout.mainDim += flexLine.layout.remainingFreeSpace / float(flexLine.numberOfAutoMargins)
814
+ if performLayout:
815
+ child.setLayoutPosition(
816
+ childLayout.position(flexStartEdge(mainAxis)) + flexLine.layout.mainDim,
817
+ flexStartEdge(mainAxis),
818
+ )
819
+ if child is not flexLine.itemsInFlow[-1]:
820
+ flexLine.layout.mainDim += betweenMainDim
821
+ if child.style().flexEndMarginIsAuto(mainAxis, direction) and flexLine.layout.remainingFreeSpace > 0.0:
822
+ flexLine.layout.mainDim += flexLine.layout.remainingFreeSpace / float(flexLine.numberOfAutoMargins)
823
+ canSkipFlex = (not performLayout) and sizingModeCrossDim == SizingMode.StretchFit
824
+ if canSkipFlex:
825
+ flexLine.layout.mainDim = float32(
826
+ flexLine.layout.mainDim
827
+ + child.style().computeMarginForAxis(mainAxis, availableInnerWidth)
828
+ + childLayout.computedFlexBasis.unwrap()
829
+ )
830
+ flexLine.layout.crossDim = availableInnerCrossDim
831
+ else:
832
+ flexLine.layout.mainDim += child.dimensionWithMargin(mainAxis, availableInnerWidth)
833
+ if nodeBaselineLayout:
834
+ ascent = calculateBaseline(child) + child.style().computeFlexStartMargin(
835
+ YGFlexDirection.YGFlexDirectionColumn, direction, availableInnerWidth
836
+ )
837
+ descent = (
838
+ child.getLayout().measuredDimension(YGDimension.YGDimensionHeight)
839
+ + child.style().computeMarginForAxis(YGFlexDirection.YGFlexDirectionColumn, availableInnerWidth)
840
+ - ascent
841
+ )
842
+ maxAscentForCurrentLine = maxOrDefined(maxAscentForCurrentLine, ascent)
843
+ maxDescentForCurrentLine = maxOrDefined(maxDescentForCurrentLine, descent)
844
+ else:
845
+ flexLine.layout.crossDim = maxOrDefined(
846
+ flexLine.layout.crossDim, child.dimensionWithMargin(crossAxis, availableInnerWidth)
847
+ )
848
+ flexLine.layout.mainDim += trailingPaddingAndBorderMain
849
+ if nodeBaselineLayout:
850
+ flexLine.layout.crossDim = maxAscentForCurrentLine + maxDescentForCurrentLine
851
+ def calculateLayout(node: Node, ownerWidth: float, ownerHeight: float, ownerDirection: YGDirection) -> None:
852
+ global gCurrentGenerationCount
853
+ Event.publish(node, Event.LayoutPassStart, EventData())
854
+ layoutMarkerData = LayoutData()
855
+ gCurrentGenerationCount += 1
856
+ node.processDimensions()
857
+ direction = node.resolveDirection(ownerDirection)
858
+ style = node.style()
859
+ width = float("nan")
860
+ widthSizingMode = SizingMode.MaxContent
861
+ if node.hasDefiniteLength(YGDimension.YGDimensionWidth, ownerWidth):
862
+ width = node.getResolvedDimension(direction, YGDimension.YGDimensionWidth, ownerWidth, ownerWidth).unwrap() + node.style().computeMarginForAxis(YGFlexDirection.YGFlexDirectionRow, ownerWidth)
863
+ widthSizingMode = SizingMode.StretchFit
864
+ elif style.resolvedMaxDimension(direction, YGDimension.YGDimensionWidth, ownerWidth, ownerWidth).isDefined():
865
+ width = style.resolvedMaxDimension(direction, YGDimension.YGDimensionWidth, ownerWidth, ownerWidth).unwrap()
866
+ widthSizingMode = SizingMode.FitContent
867
+ else:
868
+ width = ownerWidth
869
+ widthSizingMode = SizingMode.MaxContent if isnan(width) else SizingMode.StretchFit
870
+ height = float("nan")
871
+ heightSizingMode = SizingMode.MaxContent
872
+ if node.hasDefiniteLength(YGDimension.YGDimensionHeight, ownerHeight):
873
+ height = node.getResolvedDimension(direction, YGDimension.YGDimensionHeight, ownerHeight, ownerWidth).unwrap() + node.style().computeMarginForAxis(YGFlexDirection.YGFlexDirectionColumn, ownerWidth)
874
+ heightSizingMode = SizingMode.StretchFit
875
+ elif style.resolvedMaxDimension(direction, YGDimension.YGDimensionHeight, ownerHeight, ownerWidth).isDefined():
876
+ height = style.resolvedMaxDimension(direction, YGDimension.YGDimensionHeight, ownerHeight, ownerWidth).unwrap()
877
+ heightSizingMode = SizingMode.FitContent
878
+ else:
879
+ height = ownerHeight
880
+ heightSizingMode = SizingMode.MaxContent if isnan(height) else SizingMode.StretchFit
881
+ if calculateLayoutInternal(
882
+ node,
883
+ width,
884
+ height,
885
+ ownerDirection,
886
+ widthSizingMode,
887
+ heightSizingMode,
888
+ ownerWidth,
889
+ ownerHeight,
890
+ True,
891
+ LayoutPassReason.kInitial,
892
+ layoutMarkerData,
893
+ 0,
894
+ gCurrentGenerationCount,
895
+ ):
896
+ node.setPosition(node.getLayout().direction(), ownerWidth, ownerHeight)
897
+ roundLayoutResultsToPixelGrid(node, 0.0, 0.0)
898
+ Event.publish(node, Event.LayoutPassEnd, LayoutPassEndData(layoutMarkerData))
899
+
900
+
901
+ def calculateLayoutImpl(
902
+ node: Node,
903
+ availableWidth: float,
904
+ availableHeight: float,
905
+ ownerDirection: YGDirection,
906
+ widthSizingMode: SizingMode,
907
+ heightSizingMode: SizingMode,
908
+ ownerWidth: float,
909
+ ownerHeight: float,
910
+ performLayout: bool,
911
+ reason: LayoutPassReason,
912
+ layoutMarkerData: LayoutData,
913
+ depth: int,
914
+ generationCount: int,
915
+ ) -> None:
916
+ if isnan(availableWidth):
917
+ assert widthSizingMode == SizingMode.MaxContent
918
+ if isnan(availableHeight):
919
+ assert heightSizingMode == SizingMode.MaxContent
920
+ if performLayout:
921
+ layoutMarkerData.layouts += 1
922
+ else:
923
+ layoutMarkerData.measures += 1
924
+ direction = node.resolveDirection(ownerDirection)
925
+ node.setLayoutDirection(direction)
926
+ flexRowDirection = resolveDirection(YGFlexDirection.YGFlexDirectionRow, direction)
927
+ flexColumnDirection = resolveDirection(YGFlexDirection.YGFlexDirectionColumn, direction)
928
+ startEdge = YGEdge.YGEdgeLeft if direction == YGDirection.YGDirectionLTR else YGEdge.YGEdgeRight
929
+ endEdge = YGEdge.YGEdgeRight if direction == YGDirection.YGDirectionLTR else YGEdge.YGEdgeLeft
930
+ marginRowLeading = node.style().computeInlineStartMargin(flexRowDirection, direction, ownerWidth)
931
+ node.setLayoutMargin(marginRowLeading, startEdge)
932
+ marginRowTrailing = node.style().computeInlineEndMargin(flexRowDirection, direction, ownerWidth)
933
+ node.setLayoutMargin(marginRowTrailing, endEdge)
934
+ marginColumnLeading = node.style().computeInlineStartMargin(flexColumnDirection, direction, ownerWidth)
935
+ node.setLayoutMargin(marginColumnLeading, YGEdge.YGEdgeTop)
936
+ marginColumnTrailing = node.style().computeInlineEndMargin(flexColumnDirection, direction, ownerWidth)
937
+ node.setLayoutMargin(marginColumnTrailing, YGEdge.YGEdgeBottom)
938
+ marginAxisRow = marginRowLeading + marginRowTrailing
939
+ marginAxisColumn = marginColumnLeading + marginColumnTrailing
940
+ node.setLayoutBorder(node.style().computeInlineStartBorder(flexRowDirection, direction), startEdge)
941
+ node.setLayoutBorder(node.style().computeInlineEndBorder(flexRowDirection, direction), endEdge)
942
+ node.setLayoutBorder(node.style().computeInlineStartBorder(flexColumnDirection, direction), YGEdge.YGEdgeTop)
943
+ node.setLayoutBorder(node.style().computeInlineEndBorder(flexColumnDirection, direction), YGEdge.YGEdgeBottom)
944
+ node.setLayoutPadding(node.style().computeInlineStartPadding(flexRowDirection, direction, ownerWidth), startEdge)
945
+ node.setLayoutPadding(node.style().computeInlineEndPadding(flexRowDirection, direction, ownerWidth), endEdge)
946
+ node.setLayoutPadding(node.style().computeInlineStartPadding(flexColumnDirection, direction, ownerWidth), YGEdge.YGEdgeTop)
947
+ node.setLayoutPadding(node.style().computeInlineEndPadding(flexColumnDirection, direction, ownerWidth), YGEdge.YGEdgeBottom)
948
+ if node.hasMeasureFunc():
949
+ measureNodeWithMeasureFunc(
950
+ node,
951
+ direction,
952
+ availableWidth - marginAxisRow,
953
+ availableHeight - marginAxisColumn,
954
+ widthSizingMode,
955
+ heightSizingMode,
956
+ ownerWidth,
957
+ ownerHeight,
958
+ layoutMarkerData,
959
+ reason,
960
+ )
961
+ cleanupContentsNodesRecursively(node)
962
+ return
963
+ childCount = node.getLayoutChildCount()
964
+ if childCount == 0:
965
+ measureNodeWithoutChildren(
966
+ node,
967
+ direction,
968
+ availableWidth - marginAxisRow,
969
+ availableHeight - marginAxisColumn,
970
+ widthSizingMode,
971
+ heightSizingMode,
972
+ ownerWidth,
973
+ ownerHeight,
974
+ )
975
+ cleanupContentsNodesRecursively(node)
976
+ return
977
+ if not performLayout and measureNodeWithFixedSize(
978
+ node,
979
+ direction,
980
+ availableWidth - marginAxisRow,
981
+ availableHeight - marginAxisColumn,
982
+ widthSizingMode,
983
+ heightSizingMode,
984
+ ownerWidth,
985
+ ownerHeight,
986
+ ):
987
+ cleanupContentsNodesRecursively(node)
988
+ return
989
+ node.cloneChildrenIfNeeded()
990
+ node.setLayoutHadOverflow(False)
991
+ cleanupContentsNodesRecursively(node)
992
+ mainAxis = resolveDirection(node.style().flexDirection(), direction)
993
+ crossAxis = resolveCrossDirection(mainAxis, direction)
994
+ isMainAxisRow = isRow(mainAxis)
995
+ isNodeFlexWrap = node.style().flexWrap() != YGWrap.YGWrapNoWrap
996
+ mainAxisOwnerSize = ownerWidth if isMainAxisRow else ownerHeight
997
+ crossAxisOwnerSize = ownerHeight if isMainAxisRow else ownerWidth
998
+ paddingAndBorderAxisMain = paddingAndBorderForAxis(node, mainAxis, direction, ownerWidth)
999
+ paddingAndBorderAxisCross = paddingAndBorderForAxis(node, crossAxis, direction, ownerWidth)
1000
+ leadingPaddingAndBorderCross = node.style().computeFlexStartPaddingAndBorder(crossAxis, direction, ownerWidth)
1001
+ sizingModeMainDim = widthSizingMode if isMainAxisRow else heightSizingMode
1002
+ sizingModeCrossDim = heightSizingMode if isMainAxisRow else widthSizingMode
1003
+ paddingAndBorderAxisRow = paddingAndBorderAxisMain if isMainAxisRow else paddingAndBorderAxisCross
1004
+ paddingAndBorderAxisColumn = paddingAndBorderAxisCross if isMainAxisRow else paddingAndBorderAxisMain
1005
+ availableInnerWidth = calculateAvailableInnerDimension(
1006
+ node,
1007
+ direction,
1008
+ YGDimension.YGDimensionWidth,
1009
+ availableWidth - marginAxisRow,
1010
+ paddingAndBorderAxisRow,
1011
+ ownerWidth,
1012
+ ownerWidth,
1013
+ )
1014
+ availableInnerHeight = calculateAvailableInnerDimension(
1015
+ node,
1016
+ direction,
1017
+ YGDimension.YGDimensionHeight,
1018
+ availableHeight - marginAxisColumn,
1019
+ paddingAndBorderAxisColumn,
1020
+ ownerHeight,
1021
+ ownerWidth,
1022
+ )
1023
+ availableInnerMainDim = availableInnerWidth if isMainAxisRow else availableInnerHeight
1024
+ availableInnerCrossDim = availableInnerHeight if isMainAxisRow else availableInnerWidth
1025
+ totalMainDim = computeFlexBasisForChildren(
1026
+ node,
1027
+ availableInnerWidth,
1028
+ availableInnerHeight,
1029
+ widthSizingMode,
1030
+ heightSizingMode,
1031
+ direction,
1032
+ mainAxis,
1033
+ performLayout,
1034
+ layoutMarkerData,
1035
+ depth,
1036
+ generationCount,
1037
+ )
1038
+ if childCount > 1:
1039
+ totalMainDim = float32(
1040
+ totalMainDim
1041
+ + float32(
1042
+ node.style().computeGapForAxis(mainAxis, availableInnerMainDim)
1043
+ * float(childCount - 1)
1044
+ )
1045
+ )
1046
+ mainAxisOverflows = sizingModeMainDim != SizingMode.MaxContent and availableInnerMainDim == availableInnerMainDim and totalMainDim > availableInnerMainDim
1047
+ if isNodeFlexWrap and mainAxisOverflows and sizingModeMainDim == SizingMode.FitContent:
1048
+ sizingModeMainDim = SizingMode.StretchFit
1049
+ layoutChildren = list(node.getLayoutChildren())
1050
+ lineCount = 0
1051
+ totalLineCrossDim = 0.0
1052
+ crossAxisGap = node.style().computeGapForAxis(crossAxis, availableInnerCrossDim)
1053
+ maxLineMainDim = 0.0
1054
+ startIndex = 0
1055
+ while startIndex < len(layoutChildren):
1056
+ flexLine = calculateFlexLine(
1057
+ node,
1058
+ ownerDirection,
1059
+ ownerWidth,
1060
+ mainAxisOwnerSize,
1061
+ availableInnerWidth,
1062
+ availableInnerMainDim,
1063
+ layoutChildren,
1064
+ startIndex,
1065
+ lineCount,
1066
+ )
1067
+ canSkipFlex = (not performLayout) and sizingModeCrossDim == SizingMode.StretchFit
1068
+ sizeBasedOnContent = False
1069
+ if sizingModeMainDim != SizingMode.StretchFit:
1070
+ style = node.style()
1071
+ minInnerWidth = style.resolvedMinDimension(direction, YGDimension.YGDimensionWidth, ownerWidth, ownerWidth).unwrap() - paddingAndBorderAxisRow
1072
+ maxInnerWidth = style.resolvedMaxDimension(direction, YGDimension.YGDimensionWidth, ownerWidth, ownerWidth).unwrap() - paddingAndBorderAxisRow
1073
+ minInnerHeight = style.resolvedMinDimension(direction, YGDimension.YGDimensionHeight, ownerHeight, ownerWidth).unwrap() - paddingAndBorderAxisColumn
1074
+ maxInnerHeight = style.resolvedMaxDimension(direction, YGDimension.YGDimensionHeight, ownerHeight, ownerWidth).unwrap() - paddingAndBorderAxisColumn
1075
+ minInnerMainDim = minInnerWidth if isMainAxisRow else minInnerHeight
1076
+ maxInnerMainDim = maxInnerWidth if isMainAxisRow else maxInnerHeight
1077
+ if minInnerMainDim == minInnerMainDim and flexLine.sizeConsumed < minInnerMainDim:
1078
+ availableInnerMainDim = minInnerMainDim
1079
+ elif maxInnerMainDim == maxInnerMainDim and flexLine.sizeConsumed > maxInnerMainDim:
1080
+ availableInnerMainDim = maxInnerMainDim
1081
+ else:
1082
+ useLegacyStretchBehaviour = node.hasErrata(YGErrata.YGErrataStretchFlexBasis)
1083
+ if (not useLegacyStretchBehaviour) and (
1084
+ (flexLine.layout.totalFlexGrowFactors == flexLine.layout.totalFlexGrowFactors and flexLine.layout.totalFlexGrowFactors == 0)
1085
+ or (node.resolveFlexGrow() == node.resolveFlexGrow() and node.resolveFlexGrow() == 0)
1086
+ ):
1087
+ availableInnerMainDim = flexLine.sizeConsumed
1088
+ sizeBasedOnContent = not useLegacyStretchBehaviour
1089
+ if (not sizeBasedOnContent) and availableInnerMainDim == availableInnerMainDim:
1090
+ flexLine.layout.remainingFreeSpace = float32(
1091
+ availableInnerMainDim - flexLine.sizeConsumed
1092
+ )
1093
+ elif flexLine.sizeConsumed < 0:
1094
+ flexLine.layout.remainingFreeSpace = float32(-flexLine.sizeConsumed)
1095
+ if not canSkipFlex:
1096
+ resolveFlexibleLength(
1097
+ node,
1098
+ flexLine,
1099
+ mainAxis,
1100
+ crossAxis,
1101
+ direction,
1102
+ ownerWidth,
1103
+ mainAxisOwnerSize,
1104
+ availableInnerMainDim,
1105
+ availableInnerCrossDim,
1106
+ availableInnerWidth,
1107
+ availableInnerHeight,
1108
+ mainAxisOverflows,
1109
+ sizingModeCrossDim,
1110
+ performLayout,
1111
+ layoutMarkerData,
1112
+ depth,
1113
+ generationCount,
1114
+ )
1115
+ node.setLayoutHadOverflow(
1116
+ node.getLayout().hadOverflow() or (flexLine.layout.remainingFreeSpace < 0)
1117
+ )
1118
+ justifyMainAxis(
1119
+ node,
1120
+ flexLine,
1121
+ mainAxis,
1122
+ crossAxis,
1123
+ direction,
1124
+ sizingModeMainDim,
1125
+ sizingModeCrossDim,
1126
+ mainAxisOwnerSize,
1127
+ ownerWidth,
1128
+ availableInnerMainDim,
1129
+ availableInnerCrossDim,
1130
+ availableInnerWidth,
1131
+ performLayout,
1132
+ )
1133
+ containerCrossAxis = availableInnerCrossDim
1134
+ if sizingModeCrossDim in (SizingMode.MaxContent, SizingMode.FitContent):
1135
+ containerCrossAxis = (
1136
+ boundAxis(
1137
+ node,
1138
+ crossAxis,
1139
+ direction,
1140
+ flexLine.layout.crossDim + paddingAndBorderAxisCross,
1141
+ crossAxisOwnerSize,
1142
+ ownerWidth,
1143
+ )
1144
+ - paddingAndBorderAxisCross
1145
+ )
1146
+ if (not isNodeFlexWrap) and sizingModeCrossDim == SizingMode.StretchFit:
1147
+ flexLine.layout.crossDim = availableInnerCrossDim
1148
+ if not isNodeFlexWrap:
1149
+ flexLine.layout.crossDim = (
1150
+ boundAxis(
1151
+ node,
1152
+ crossAxis,
1153
+ direction,
1154
+ flexLine.layout.crossDim + paddingAndBorderAxisCross,
1155
+ crossAxisOwnerSize,
1156
+ ownerWidth,
1157
+ )
1158
+ - paddingAndBorderAxisCross
1159
+ )
1160
+ if performLayout:
1161
+ for child in flexLine.itemsInFlow:
1162
+ leadingCrossDim = leadingPaddingAndBorderCross
1163
+ alignItem = resolveChildAlignment(node, child)
1164
+ if (
1165
+ alignItem == YGAlign.YGAlignStretch
1166
+ and not child.style().flexStartMarginIsAuto(crossAxis, direction)
1167
+ and not child.style().flexEndMarginIsAuto(crossAxis, direction)
1168
+ ):
1169
+ if not child.hasDefiniteLength(dimension(crossAxis), availableInnerCrossDim):
1170
+ childMainSize = child.getLayout().measuredDimension(dimension(mainAxis))
1171
+ childStyle = child.style()
1172
+ if childStyle.aspectRatio().isDefined():
1173
+ childCrossSize = child.style().computeMarginForAxis(crossAxis, availableInnerWidth) + (
1174
+ childMainSize / childStyle.aspectRatio().unwrap()
1175
+ if isMainAxisRow
1176
+ else childMainSize * childStyle.aspectRatio().unwrap()
1177
+ )
1178
+ else:
1179
+ childCrossSize = flexLine.layout.crossDim
1180
+ childMainSize += child.style().computeMarginForAxis(mainAxis, availableInnerWidth)
1181
+ childMainSizingMode = SizingMode.StretchFit
1182
+ childCrossSizingMode = SizingMode.StretchFit
1183
+ childMainSizingMode, childMainSize = constrainMaxSizeForMode(
1184
+ child, direction, mainAxis, availableInnerMainDim, availableInnerWidth, childMainSizingMode, childMainSize
1185
+ )
1186
+ childCrossSizingMode, childCrossSize = constrainMaxSizeForMode(
1187
+ child, direction, crossAxis, availableInnerCrossDim, availableInnerWidth, childCrossSizingMode, childCrossSize
1188
+ )
1189
+ childWidth = childMainSize if isMainAxisRow else childCrossSize
1190
+ childHeight = childMainSize if not isMainAxisRow else childCrossSize
1191
+ alignContent = node.style().alignContent()
1192
+ crossAxisDoesNotGrow = alignContent != YGAlign.YGAlignStretch and isNodeFlexWrap
1193
+ childWidthSizingMode = (
1194
+ SizingMode.MaxContent if isnan(childWidth) or ((not isMainAxisRow) and crossAxisDoesNotGrow) else SizingMode.StretchFit
1195
+ )
1196
+ childHeightSizingMode = (
1197
+ SizingMode.MaxContent if isnan(childHeight) or (isMainAxisRow and crossAxisDoesNotGrow) else SizingMode.StretchFit
1198
+ )
1199
+ calculateLayoutInternal(
1200
+ child,
1201
+ childWidth,
1202
+ childHeight,
1203
+ direction,
1204
+ childWidthSizingMode,
1205
+ childHeightSizingMode,
1206
+ availableInnerWidth,
1207
+ availableInnerHeight,
1208
+ True,
1209
+ LayoutPassReason.kStretch,
1210
+ layoutMarkerData,
1211
+ depth,
1212
+ generationCount,
1213
+ )
1214
+ else:
1215
+ remainingCrossDim = containerCrossAxis - child.dimensionWithMargin(crossAxis, availableInnerWidth)
1216
+ if child.style().flexStartMarginIsAuto(crossAxis, direction) and child.style().flexEndMarginIsAuto(crossAxis, direction):
1217
+ leadingCrossDim += maxOrDefined(0.0, remainingCrossDim / 2)
1218
+ elif child.style().flexEndMarginIsAuto(crossAxis, direction):
1219
+ pass
1220
+ elif child.style().flexStartMarginIsAuto(crossAxis, direction):
1221
+ leadingCrossDim += maxOrDefined(0.0, remainingCrossDim)
1222
+ elif alignItem == YGAlign.YGAlignCenter:
1223
+ leadingCrossDim += remainingCrossDim / 2
1224
+ elif alignItem not in (YGAlign.YGAlignFlexStart,):
1225
+ leadingCrossDim += remainingCrossDim
1226
+ child.setLayoutPosition(
1227
+ child.getLayout().position(flexStartEdge(crossAxis)) + totalLineCrossDim + leadingCrossDim,
1228
+ flexStartEdge(crossAxis),
1229
+ )
1230
+ appliedCrossGap = crossAxisGap if lineCount != 0 else 0.0
1231
+ totalLineCrossDim += flexLine.layout.crossDim + appliedCrossGap
1232
+ maxLineMainDim = maxOrDefined(maxLineMainDim, flexLine.layout.mainDim)
1233
+ nextStartIndex = startIndex
1234
+ lineChildIndex = 0
1235
+ while nextStartIndex < len(layoutChildren):
1236
+ child = layoutChildren[nextStartIndex]
1237
+ if child.style().display() == YGDisplay.YGDisplayNone or child.style().positionType() == YGPositionType.YGPositionTypeAbsolute:
1238
+ nextStartIndex += 1
1239
+ continue
1240
+
1241
+ if lineChildIndex < len(flexLine.itemsInFlow) and child == flexLine.itemsInFlow[lineChildIndex]:
1242
+ lineChildIndex += 1
1243
+ nextStartIndex += 1
1244
+ if lineChildIndex == len(flexLine.itemsInFlow):
1245
+ break
1246
+ continue
1247
+
1248
+ break
1249
+
1250
+ while nextStartIndex < len(layoutChildren):
1251
+ child = layoutChildren[nextStartIndex]
1252
+ if child.style().display() == YGDisplay.YGDisplayNone or child.style().positionType() == YGPositionType.YGPositionTypeAbsolute:
1253
+ nextStartIndex += 1
1254
+ continue
1255
+ break
1256
+
1257
+ startIndex = nextStartIndex
1258
+ lineCount += 1
1259
+ if performLayout and (isNodeFlexWrap or isBaselineLayout(node)):
1260
+ leadPerLine = 0.0
1261
+ currentLead = leadingPaddingAndBorderCross
1262
+ extraSpacePerLine = 0.0
1263
+ if sizingModeCrossDim == SizingMode.StretchFit:
1264
+ unclampedCrossDim = availableInnerCrossDim + paddingAndBorderAxisCross
1265
+ elif node.hasDefiniteLength(dimension(crossAxis), crossAxisOwnerSize):
1266
+ unclampedCrossDim = node.getResolvedDimension(
1267
+ direction,
1268
+ dimension(crossAxis),
1269
+ crossAxisOwnerSize,
1270
+ ownerWidth,
1271
+ ).unwrap()
1272
+ else:
1273
+ unclampedCrossDim = totalLineCrossDim + paddingAndBorderAxisCross
1274
+ innerCrossDim = (
1275
+ boundAxis(
1276
+ node,
1277
+ crossAxis,
1278
+ direction,
1279
+ unclampedCrossDim,
1280
+ crossAxisOwnerSize,
1281
+ ownerWidth,
1282
+ )
1283
+ - paddingAndBorderAxisCross
1284
+ )
1285
+ remainingAlignContentDim = innerCrossDim - totalLineCrossDim
1286
+ alignContent = (
1287
+ node.style().alignContent()
1288
+ if remainingAlignContentDim >= 0
1289
+ else fallbackAlignment(node.style().alignContent())
1290
+ )
1291
+ if alignContent == YGAlign.YGAlignFlexEnd:
1292
+ currentLead += remainingAlignContentDim
1293
+ elif alignContent == YGAlign.YGAlignCenter:
1294
+ currentLead += remainingAlignContentDim / 2
1295
+ elif alignContent == YGAlign.YGAlignStretch:
1296
+ extraSpacePerLine = floatDivision(
1297
+ remainingAlignContentDim, float(lineCount)
1298
+ )
1299
+ elif alignContent == YGAlign.YGAlignSpaceAround:
1300
+ currentLead += floatDivision(
1301
+ remainingAlignContentDim, 2 * float(lineCount)
1302
+ )
1303
+ leadPerLine = floatDivision(
1304
+ remainingAlignContentDim, float(lineCount)
1305
+ )
1306
+ elif alignContent == YGAlign.YGAlignSpaceEvenly:
1307
+ currentLead += remainingAlignContentDim / float(lineCount + 1)
1308
+ leadPerLine = remainingAlignContentDim / float(lineCount + 1)
1309
+ elif alignContent == YGAlign.YGAlignSpaceBetween and lineCount > 1:
1310
+ leadPerLine = remainingAlignContentDim / float(lineCount - 1)
1311
+ endIndex = 0
1312
+ for i in range(lineCount):
1313
+ startLineIndex = endIndex
1314
+ lineHeight = 0.0
1315
+ maxAscentForCurrentLine = 0.0
1316
+ maxDescentForCurrentLine = 0.0
1317
+ while endIndex < len(layoutChildren):
1318
+ child = layoutChildren[endIndex]
1319
+ endIndex += 1
1320
+ if child.style().display() == YGDisplay.YGDisplayNone:
1321
+ continue
1322
+ if child.style().positionType() != YGPositionType.YGPositionTypeAbsolute:
1323
+ if child.getLineIndex() != i:
1324
+ endIndex -= 1
1325
+ break
1326
+ if child.isLayoutDimensionDefined(crossAxis):
1327
+ lineHeight = maxOrDefined(
1328
+ lineHeight,
1329
+ child.getLayout().measuredDimension(dimension(crossAxis))
1330
+ + child.style().computeMarginForAxis(crossAxis, availableInnerWidth),
1331
+ )
1332
+ if resolveChildAlignment(node, child) == YGAlign.YGAlignBaseline:
1333
+ ascent = calculateBaseline(child) + child.style().computeFlexStartMargin(
1334
+ YGFlexDirection.YGFlexDirectionColumn, direction, availableInnerWidth
1335
+ )
1336
+ descent = (
1337
+ child.getLayout().measuredDimension(YGDimension.YGDimensionHeight)
1338
+ + child.style().computeMarginForAxis(YGFlexDirection.YGFlexDirectionColumn, availableInnerWidth)
1339
+ - ascent
1340
+ )
1341
+ maxAscentForCurrentLine = maxOrDefined(maxAscentForCurrentLine, ascent)
1342
+ maxDescentForCurrentLine = maxOrDefined(maxDescentForCurrentLine, descent)
1343
+ lineHeight = maxOrDefined(lineHeight, maxAscentForCurrentLine + maxDescentForCurrentLine)
1344
+ currentLead += crossAxisGap if i != 0 else 0.0
1345
+ lineHeight += extraSpacePerLine
1346
+ for child in layoutChildren[startLineIndex:endIndex]:
1347
+ if child.style().display() == YGDisplay.YGDisplayNone:
1348
+ continue
1349
+ if child.style().positionType() != YGPositionType.YGPositionTypeAbsolute:
1350
+ childAlignment = resolveChildAlignment(node, child)
1351
+ if childAlignment == YGAlign.YGAlignFlexStart:
1352
+ child.setLayoutPosition(
1353
+ currentLead + child.style().computeFlexStartPosition(crossAxis, direction, availableInnerWidth),
1354
+ flexStartEdge(crossAxis),
1355
+ )
1356
+ elif childAlignment == YGAlign.YGAlignFlexEnd:
1357
+ child.setLayoutPosition(
1358
+ currentLead
1359
+ + lineHeight
1360
+ - child.style().computeFlexEndMargin(crossAxis, direction, availableInnerWidth)
1361
+ - child.getLayout().measuredDimension(dimension(crossAxis)),
1362
+ flexStartEdge(crossAxis),
1363
+ )
1364
+ elif childAlignment == YGAlign.YGAlignCenter:
1365
+ childHeight = child.getLayout().measuredDimension(dimension(crossAxis))
1366
+ child.setLayoutPosition(
1367
+ currentLead + (lineHeight - childHeight) / 2,
1368
+ flexStartEdge(crossAxis),
1369
+ )
1370
+ elif childAlignment == YGAlign.YGAlignStretch:
1371
+ child.setLayoutPosition(
1372
+ currentLead + child.style().computeFlexStartMargin(crossAxis, direction, availableInnerWidth),
1373
+ flexStartEdge(crossAxis),
1374
+ )
1375
+ if not child.hasDefiniteLength(dimension(crossAxis), availableInnerCrossDim):
1376
+ childWidth = (
1377
+ child.getLayout().measuredDimension(YGDimension.YGDimensionWidth)
1378
+ + child.style().computeMarginForAxis(mainAxis, availableInnerWidth)
1379
+ if isMainAxisRow
1380
+ else leadPerLine + lineHeight
1381
+ )
1382
+ childHeight = (
1383
+ child.getLayout().measuredDimension(YGDimension.YGDimensionHeight)
1384
+ + child.style().computeMarginForAxis(crossAxis, availableInnerWidth)
1385
+ if not isMainAxisRow
1386
+ else leadPerLine + lineHeight
1387
+ )
1388
+ if not (
1389
+ inexactEquals(
1390
+ childWidth,
1391
+ child.getLayout().measuredDimension(YGDimension.YGDimensionWidth),
1392
+ )
1393
+ and inexactEquals(
1394
+ childHeight,
1395
+ child.getLayout().measuredDimension(YGDimension.YGDimensionHeight),
1396
+ )
1397
+ ):
1398
+ calculateLayoutInternal(
1399
+ child,
1400
+ childWidth,
1401
+ childHeight,
1402
+ direction,
1403
+ SizingMode.StretchFit,
1404
+ SizingMode.StretchFit,
1405
+ availableInnerWidth,
1406
+ availableInnerHeight,
1407
+ True,
1408
+ LayoutPassReason.kMultilineStretch,
1409
+ layoutMarkerData,
1410
+ depth,
1411
+ generationCount,
1412
+ )
1413
+ elif childAlignment == YGAlign.YGAlignBaseline:
1414
+ child.setLayoutPosition(
1415
+ currentLead
1416
+ + maxAscentForCurrentLine
1417
+ - calculateBaseline(child)
1418
+ + child.style().computeFlexStartPosition(
1419
+ YGFlexDirection.YGFlexDirectionColumn,
1420
+ direction,
1421
+ availableInnerCrossDim,
1422
+ ),
1423
+ YGEdge.YGEdgeTop,
1424
+ )
1425
+ currentLead = currentLead + leadPerLine + lineHeight
1426
+ node.setLayoutMeasuredDimension(
1427
+ boundAxis(node, YGFlexDirection.YGFlexDirectionRow, direction, availableWidth - marginAxisRow, ownerWidth, ownerWidth),
1428
+ YGDimension.YGDimensionWidth,
1429
+ )
1430
+ node.setLayoutMeasuredDimension(
1431
+ boundAxis(node, YGFlexDirection.YGFlexDirectionColumn, direction, availableHeight - marginAxisColumn, ownerHeight, ownerWidth),
1432
+ YGDimension.YGDimensionHeight,
1433
+ )
1434
+ if sizingModeMainDim == SizingMode.MaxContent or (
1435
+ node.style().overflow() != YGOverflow.YGOverflowScroll and sizingModeMainDim == SizingMode.FitContent
1436
+ ):
1437
+ node.setLayoutMeasuredDimension(
1438
+ boundAxis(node, mainAxis, direction, maxLineMainDim, mainAxisOwnerSize, ownerWidth),
1439
+ dimension(mainAxis),
1440
+ )
1441
+ elif sizingModeMainDim == SizingMode.FitContent and node.style().overflow() == YGOverflow.YGOverflowScroll:
1442
+ node.setLayoutMeasuredDimension(
1443
+ maxOrDefined(
1444
+ minOrDefined(
1445
+ availableInnerMainDim + paddingAndBorderAxisMain,
1446
+ boundAxisWithinMinAndMax(
1447
+ node, direction, mainAxis, FloatOptional(maxLineMainDim), mainAxisOwnerSize, ownerWidth
1448
+ ).unwrap(),
1449
+ ),
1450
+ paddingAndBorderAxisMain,
1451
+ ),
1452
+ dimension(mainAxis),
1453
+ )
1454
+ if sizingModeCrossDim == SizingMode.MaxContent or (
1455
+ node.style().overflow() != YGOverflow.YGOverflowScroll and sizingModeCrossDim == SizingMode.FitContent
1456
+ ):
1457
+ node.setLayoutMeasuredDimension(
1458
+ boundAxis(node, crossAxis, direction, totalLineCrossDim + paddingAndBorderAxisCross, crossAxisOwnerSize, ownerWidth),
1459
+ dimension(crossAxis),
1460
+ )
1461
+ elif sizingModeCrossDim == SizingMode.FitContent and node.style().overflow() == YGOverflow.YGOverflowScroll:
1462
+ node.setLayoutMeasuredDimension(
1463
+ maxOrDefined(
1464
+ minOrDefined(
1465
+ availableInnerCrossDim + paddingAndBorderAxisCross,
1466
+ boundAxisWithinMinAndMax(
1467
+ node,
1468
+ direction,
1469
+ crossAxis,
1470
+ FloatOptional(totalLineCrossDim + paddingAndBorderAxisCross),
1471
+ crossAxisOwnerSize,
1472
+ ownerWidth,
1473
+ ).unwrap(),
1474
+ ),
1475
+ paddingAndBorderAxisCross,
1476
+ ),
1477
+ dimension(crossAxis),
1478
+ )
1479
+ if performLayout and node.style().flexWrap() == YGWrap.YGWrapWrapReverse:
1480
+ for child in node.getLayoutChildren():
1481
+ if child.style().positionType() != YGPositionType.YGPositionTypeAbsolute:
1482
+ child.setLayoutPosition(
1483
+ node.getLayout().measuredDimension(dimension(crossAxis))
1484
+ - child.getLayout().position(flexStartEdge(crossAxis))
1485
+ - child.getLayout().measuredDimension(dimension(crossAxis)),
1486
+ flexStartEdge(crossAxis),
1487
+ )
1488
+ if performLayout:
1489
+ needsMainTrailingPos = needsTrailingPosition(mainAxis)
1490
+ needsCrossTrailingPos = needsTrailingPosition(crossAxis)
1491
+ if needsMainTrailingPos or needsCrossTrailingPos:
1492
+ for child in node.getLayoutChildren():
1493
+ if child.style().display() == YGDisplay.YGDisplayNone or child.style().positionType() == YGPositionType.YGPositionTypeAbsolute:
1494
+ continue
1495
+ if needsMainTrailingPos:
1496
+ setChildTrailingPosition(node, child, mainAxis)
1497
+ if needsCrossTrailingPos:
1498
+ setChildTrailingPosition(node, child, crossAxis)
1499
+ if node.style().positionType() != YGPositionType.YGPositionTypeStatic or node.alwaysFormsContainingBlock() or depth == 1:
1500
+ layoutAbsoluteDescendants(
1501
+ node,
1502
+ node,
1503
+ sizingModeMainDim if isMainAxisRow else sizingModeCrossDim,
1504
+ direction,
1505
+ layoutMarkerData,
1506
+ depth,
1507
+ generationCount,
1508
+ 0.0,
1509
+ 0.0,
1510
+ availableInnerWidth,
1511
+ availableInnerHeight,
1512
+ )
1513
+
1514
+
1515
+ def calculateLayoutInternal(
1516
+ node: Node,
1517
+ availableWidth: float,
1518
+ availableHeight: float,
1519
+ ownerDirection: YGDirection,
1520
+ widthSizingMode: SizingMode,
1521
+ heightSizingMode: SizingMode,
1522
+ ownerWidth: float,
1523
+ ownerHeight: float,
1524
+ performLayout: bool,
1525
+ reason: LayoutPassReason,
1526
+ layoutMarkerData: LayoutData,
1527
+ depth: int,
1528
+ generationCount: int,
1529
+ ) -> bool:
1530
+ layout = node.getLayout()
1531
+ depth += 1
1532
+ needToVisitNode = (
1533
+ (node.isDirty() and layout.generationCount != generationCount)
1534
+ or layout.configVersion != node.getConfig().getVersion()
1535
+ or layout.lastOwnerDirection != ownerDirection
1536
+ )
1537
+ if needToVisitNode:
1538
+ layout.nextCachedMeasurementsIndex = 0
1539
+ layout.cachedLayout.availableWidth = -1
1540
+ layout.cachedLayout.availableHeight = -1
1541
+ layout.cachedLayout.widthSizingMode = SizingMode.MaxContent
1542
+ layout.cachedLayout.heightSizingMode = SizingMode.MaxContent
1543
+ layout.cachedLayout.computedWidth = -1
1544
+ layout.cachedLayout.computedHeight = -1
1545
+ cachedResults = None
1546
+ if node.hasMeasureFunc():
1547
+ marginAxisRow = node.style().computeMarginForAxis(YGFlexDirection.YGFlexDirectionRow, ownerWidth)
1548
+ marginAxisColumn = node.style().computeMarginForAxis(YGFlexDirection.YGFlexDirectionColumn, ownerWidth)
1549
+ if canUseCachedMeasurement(
1550
+ widthSizingMode,
1551
+ availableWidth,
1552
+ heightSizingMode,
1553
+ availableHeight,
1554
+ layout.cachedLayout.widthSizingMode,
1555
+ layout.cachedLayout.availableWidth,
1556
+ layout.cachedLayout.heightSizingMode,
1557
+ layout.cachedLayout.availableHeight,
1558
+ layout.cachedLayout.computedWidth,
1559
+ layout.cachedLayout.computedHeight,
1560
+ marginAxisRow,
1561
+ marginAxisColumn,
1562
+ node.getConfig(),
1563
+ ):
1564
+ cachedResults = layout.cachedLayout
1565
+ else:
1566
+ for measurement in layout.cachedMeasurements[: layout.nextCachedMeasurementsIndex]:
1567
+ if canUseCachedMeasurement(
1568
+ widthSizingMode,
1569
+ availableWidth,
1570
+ heightSizingMode,
1571
+ availableHeight,
1572
+ measurement.widthSizingMode,
1573
+ measurement.availableWidth,
1574
+ measurement.heightSizingMode,
1575
+ measurement.availableHeight,
1576
+ measurement.computedWidth,
1577
+ measurement.computedHeight,
1578
+ marginAxisRow,
1579
+ marginAxisColumn,
1580
+ node.getConfig(),
1581
+ ):
1582
+ cachedResults = measurement
1583
+ break
1584
+ elif performLayout:
1585
+ if (
1586
+ inexactEquals(availableWidth, layout.cachedLayout.availableWidth)
1587
+ and inexactEquals(availableHeight, layout.cachedLayout.availableHeight)
1588
+ and layout.cachedLayout.widthSizingMode == widthSizingMode
1589
+ and layout.cachedLayout.heightSizingMode == heightSizingMode
1590
+ ):
1591
+ cachedResults = layout.cachedLayout
1592
+ else:
1593
+ for measurement in layout.cachedMeasurements[: layout.nextCachedMeasurementsIndex]:
1594
+ if (
1595
+ inexactEquals(availableWidth, measurement.availableWidth)
1596
+ and inexactEquals(availableHeight, measurement.availableHeight)
1597
+ and measurement.widthSizingMode == widthSizingMode
1598
+ and measurement.heightSizingMode == heightSizingMode
1599
+ ):
1600
+ cachedResults = measurement
1601
+ break
1602
+ if (not needToVisitNode) and cachedResults is not None:
1603
+ layout.setMeasuredDimension(YGDimension.YGDimensionWidth, cachedResults.computedWidth)
1604
+ layout.setMeasuredDimension(YGDimension.YGDimensionHeight, cachedResults.computedHeight)
1605
+ if performLayout:
1606
+ layoutMarkerData.cachedLayouts += 1
1607
+ else:
1608
+ layoutMarkerData.cachedMeasures += 1
1609
+ else:
1610
+ calculateLayoutImpl(
1611
+ node,
1612
+ availableWidth,
1613
+ availableHeight,
1614
+ ownerDirection,
1615
+ widthSizingMode,
1616
+ heightSizingMode,
1617
+ ownerWidth,
1618
+ ownerHeight,
1619
+ performLayout,
1620
+ reason,
1621
+ layoutMarkerData,
1622
+ depth,
1623
+ generationCount,
1624
+ )
1625
+ layout.lastOwnerDirection = ownerDirection
1626
+ layout.configVersion = node.getConfig().getVersion()
1627
+ if cachedResults is None:
1628
+ layoutMarkerData.maxMeasureCache = max(layoutMarkerData.maxMeasureCache, layout.nextCachedMeasurementsIndex + 1)
1629
+ if layout.nextCachedMeasurementsIndex == LayoutResults.MaxCachedMeasurements:
1630
+ layout.nextCachedMeasurementsIndex = 0
1631
+ newCacheEntry = layout.cachedLayout if performLayout else layout.cachedMeasurements[layout.nextCachedMeasurementsIndex]
1632
+ if not performLayout:
1633
+ layout.nextCachedMeasurementsIndex += 1
1634
+ newCacheEntry.availableWidth = availableWidth
1635
+ newCacheEntry.availableHeight = availableHeight
1636
+ newCacheEntry.widthSizingMode = widthSizingMode
1637
+ newCacheEntry.heightSizingMode = heightSizingMode
1638
+ newCacheEntry.computedWidth = layout.measuredDimension(YGDimension.YGDimensionWidth)
1639
+ newCacheEntry.computedHeight = layout.measuredDimension(YGDimension.YGDimensionHeight)
1640
+ if performLayout:
1641
+ node.setLayoutDimension(layout.measuredDimension(YGDimension.YGDimensionWidth), YGDimension.YGDimensionWidth)
1642
+ node.setLayoutDimension(layout.measuredDimension(YGDimension.YGDimensionHeight), YGDimension.YGDimensionHeight)
1643
+ node.setHasNewLayout(True)
1644
+ node.setDirty(False)
1645
+ layout.generationCount = generationCount
1646
+ if performLayout:
1647
+ layoutType = LayoutType.kCachedLayout if ((not needToVisitNode) and cachedResults is layout.cachedLayout) else LayoutType.kLayout
1648
+ else:
1649
+ layoutType = LayoutType.kCachedMeasure if cachedResults is not None else LayoutType.kMeasure
1650
+ Event.publish(node, Event.NodeLayout, NodeLayoutData(layoutType))
1651
+ return needToVisitNode or cachedResults is None