1 /*
<lambda>null2 * Copyright 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.google.accompanist.adaptive
18
19 import androidx.compose.runtime.Immutable
20 import androidx.compose.runtime.Stable
21 import androidx.compose.ui.Alignment
22 import androidx.compose.ui.layout.AlignmentLine
23 import androidx.compose.ui.layout.IntrinsicMeasurable
24 import androidx.compose.ui.layout.Measured
25 import androidx.compose.ui.layout.ParentDataModifier
26 import androidx.compose.ui.layout.Placeable
27 import androidx.compose.ui.platform.InspectorInfo
28 import androidx.compose.ui.platform.InspectorValueInfo
29 import androidx.compose.ui.unit.Constraints
30 import androidx.compose.ui.unit.Density
31 import androidx.compose.ui.unit.LayoutDirection
32 import androidx.compose.ui.util.fastForEach
33 import com.google.accompanist.adaptive.LayoutOrientation.Horizontal
34 import com.google.accompanist.adaptive.LayoutOrientation.Vertical
35 import kotlin.math.max
36 import kotlin.math.min
37 import kotlin.math.roundToInt
38
39 /**
40 * Copied from:
41 * RowColumnImpl.kt
42 * https://android-review.googlesource.com/c/platform/frameworks/support/+/2260390/27/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl.kt
43 *
44 * The only changes were updating access modifiers and removing unused code
45 */
46
47 /**
48 * [Row] will be [Horizontal], [Column] is [Vertical].
49 */
50 internal enum class LayoutOrientation {
51 Horizontal,
52 Vertical
53 }
54
55 /**
56 * Used to specify the alignment of a layout's children, in cross axis direction.
57 */
58 @Immutable
59 internal sealed class CrossAxisAlignment {
60 /**
61 * Aligns to [size]. If this is a vertical alignment, [layoutDirection] should be
62 * [LayoutDirection.Ltr].
63 *
64 * @param size The remaining space (total size - content size) in the container.
65 * @param layoutDirection The layout direction of the content if horizontal or
66 * [LayoutDirection.Ltr] if vertical.
67 * @param placeable The item being aligned.
68 * @param beforeCrossAxisAlignmentLine The space before the cross-axis alignment line if
69 * an alignment line is being used or 0 if no alignment line is being used.
70 */
alignnull71 internal abstract fun align(
72 size: Int,
73 layoutDirection: LayoutDirection,
74 placeable: Placeable,
75 beforeCrossAxisAlignmentLine: Int
76 ): Int
77
78 /**
79 * Returns `true` if this is [Relative].
80 */
81 internal open val isRelative: Boolean
82 get() = false
83
84 /**
85 * Returns the alignment line position relative to the left/top of the space or `null` if
86 * this alignment doesn't rely on alignment lines.
87 */
88 internal open fun calculateAlignmentLinePosition(placeable: Placeable): Int? = null
89
90 companion object {
91 /**
92 * Place children such that their center is in the middle of the cross axis.
93 */
94 @Stable
95 val Center: CrossAxisAlignment = CenterCrossAxisAlignment
96
97 /**
98 * Place children such that their start edge is aligned to the start edge of the cross
99 * axis. TODO(popam): Consider rtl directionality.
100 */
101 @Stable
102 val Start: CrossAxisAlignment = StartCrossAxisAlignment
103
104 /**
105 * Place children such that their end edge is aligned to the end edge of the cross
106 * axis. TODO(popam): Consider rtl directionality.
107 */
108 @Stable
109 val End: CrossAxisAlignment = EndCrossAxisAlignment
110
111 /**
112 * Align children by their baseline.
113 */
114 fun AlignmentLine(alignmentLine: AlignmentLine): CrossAxisAlignment =
115 AlignmentLineCrossAxisAlignment(AlignmentLineProvider.Value(alignmentLine))
116
117 /**
118 * Align children relative to their siblings using the alignment line provided as a
119 * parameter using [AlignmentLineProvider].
120 */
121 internal fun Relative(alignmentLineProvider: AlignmentLineProvider): CrossAxisAlignment =
122 AlignmentLineCrossAxisAlignment(alignmentLineProvider)
123
124 /**
125 * Align children with vertical alignment.
126 */
127 internal fun vertical(vertical: Alignment.Vertical): CrossAxisAlignment =
128 VerticalCrossAxisAlignment(vertical)
129
130 /**
131 * Align children with horizontal alignment.
132 */
133 internal fun horizontal(horizontal: Alignment.Horizontal): CrossAxisAlignment =
134 HorizontalCrossAxisAlignment(horizontal)
135 }
136
137 private object CenterCrossAxisAlignment : CrossAxisAlignment() {
alignnull138 override fun align(
139 size: Int,
140 layoutDirection: LayoutDirection,
141 placeable: Placeable,
142 beforeCrossAxisAlignmentLine: Int
143 ): Int {
144 return size / 2
145 }
146 }
147
148 private object StartCrossAxisAlignment : CrossAxisAlignment() {
alignnull149 override fun align(
150 size: Int,
151 layoutDirection: LayoutDirection,
152 placeable: Placeable,
153 beforeCrossAxisAlignmentLine: Int
154 ): Int {
155 return if (layoutDirection == LayoutDirection.Ltr) 0 else size
156 }
157 }
158
159 private object EndCrossAxisAlignment : CrossAxisAlignment() {
alignnull160 override fun align(
161 size: Int,
162 layoutDirection: LayoutDirection,
163 placeable: Placeable,
164 beforeCrossAxisAlignmentLine: Int
165 ): Int {
166 return if (layoutDirection == LayoutDirection.Ltr) size else 0
167 }
168 }
169
170 private class AlignmentLineCrossAxisAlignment(
171 val alignmentLineProvider: AlignmentLineProvider
172 ) : CrossAxisAlignment() {
173 override val isRelative: Boolean
174 get() = true
175
calculateAlignmentLinePositionnull176 override fun calculateAlignmentLinePosition(placeable: Placeable): Int {
177 return alignmentLineProvider.calculateAlignmentLinePosition(placeable)
178 }
179
alignnull180 override fun align(
181 size: Int,
182 layoutDirection: LayoutDirection,
183 placeable: Placeable,
184 beforeCrossAxisAlignmentLine: Int
185 ): Int {
186 val alignmentLinePosition =
187 alignmentLineProvider.calculateAlignmentLinePosition(placeable)
188 return if (alignmentLinePosition != AlignmentLine.Unspecified) {
189 val line = beforeCrossAxisAlignmentLine - alignmentLinePosition
190 if (layoutDirection == LayoutDirection.Rtl) {
191 size - line
192 } else {
193 line
194 }
195 } else {
196 0
197 }
198 }
199 }
200
201 private class VerticalCrossAxisAlignment(
202 val vertical: Alignment.Vertical
203 ) : CrossAxisAlignment() {
alignnull204 override fun align(
205 size: Int,
206 layoutDirection: LayoutDirection,
207 placeable: Placeable,
208 beforeCrossAxisAlignmentLine: Int
209 ): Int {
210 return vertical.align(0, size)
211 }
212 }
213
214 private class HorizontalCrossAxisAlignment(
215 val horizontal: Alignment.Horizontal
216 ) : CrossAxisAlignment() {
alignnull217 override fun align(
218 size: Int,
219 layoutDirection: LayoutDirection,
220 placeable: Placeable,
221 beforeCrossAxisAlignmentLine: Int
222 ): Int {
223 return horizontal.align(0, size, layoutDirection)
224 }
225 }
226 }
227
228 /**
229 * Box [Constraints], but which abstract away width and height in favor of main axis and cross axis.
230 */
231 internal data class OrientationIndependentConstraints(
232 val mainAxisMin: Int,
233 val mainAxisMax: Int,
234 val crossAxisMin: Int,
235 val crossAxisMax: Int
236 ) {
237 constructor(c: Constraints, orientation: LayoutOrientation) : this(
238 if (orientation === Horizontal) c.minWidth else c.minHeight,
239 if (orientation === Horizontal) c.maxWidth else c.maxHeight,
240 if (orientation === Horizontal) c.minHeight else c.minWidth,
241 if (orientation === Horizontal) c.maxHeight else c.maxWidth
242 )
243
244 // Creates a new instance with the same main axis constraints and maximum tight cross axis.
stretchCrossAxisnull245 fun stretchCrossAxis() = OrientationIndependentConstraints(
246 mainAxisMin,
247 mainAxisMax,
248 if (crossAxisMax != Constraints.Infinity) crossAxisMax else crossAxisMin,
249 crossAxisMax
250 )
251
252 // Given an orientation, resolves the current instance to traditional constraints.
253 fun toBoxConstraints(orientation: LayoutOrientation) =
254 if (orientation === Horizontal) {
255 Constraints(mainAxisMin, mainAxisMax, crossAxisMin, crossAxisMax)
256 } else {
257 Constraints(crossAxisMin, crossAxisMax, mainAxisMin, mainAxisMax)
258 }
259
260 // Given an orientation, resolves the max width constraint this instance represents.
maxWidthnull261 fun maxWidth(orientation: LayoutOrientation) =
262 if (orientation === Horizontal) {
263 mainAxisMax
264 } else {
265 crossAxisMax
266 }
267
268 // Given an orientation, resolves the max height constraint this instance represents.
maxHeightnull269 fun maxHeight(orientation: LayoutOrientation) =
270 if (orientation === Horizontal) {
271 crossAxisMax
272 } else {
273 mainAxisMax
274 }
275 }
276
277 internal val IntrinsicMeasurable.rowColumnParentData: RowColumnParentData?
278 get() = parentData as? RowColumnParentData
279
280 internal val RowColumnParentData?.weight: Float
281 get() = this?.weight ?: 0f
282
283 internal val RowColumnParentData?.fill: Boolean
284 get() = this?.fill ?: true
285
286 internal val RowColumnParentData?.crossAxisAlignment: CrossAxisAlignment?
287 get() = this?.crossAxisAlignment
288
289 internal val RowColumnParentData?.isRelative: Boolean
290 get() = this.crossAxisAlignment?.isRelative ?: false
291
MinIntrinsicWidthMeasureBlocknull292 internal fun MinIntrinsicWidthMeasureBlock(orientation: LayoutOrientation) =
293 if (orientation == Horizontal) {
294 IntrinsicMeasureBlocks.HorizontalMinWidth
295 } else {
296 IntrinsicMeasureBlocks.VerticalMinWidth
297 }
298
MinIntrinsicHeightMeasureBlocknull299 internal fun MinIntrinsicHeightMeasureBlock(orientation: LayoutOrientation) =
300 if (orientation == Horizontal) {
301 IntrinsicMeasureBlocks.HorizontalMinHeight
302 } else {
303 IntrinsicMeasureBlocks.VerticalMinHeight
304 }
305
MaxIntrinsicWidthMeasureBlocknull306 internal fun MaxIntrinsicWidthMeasureBlock(orientation: LayoutOrientation) =
307 if (orientation == Horizontal) {
308 IntrinsicMeasureBlocks.HorizontalMaxWidth
309 } else {
310 IntrinsicMeasureBlocks.VerticalMaxWidth
311 }
312
MaxIntrinsicHeightMeasureBlocknull313 internal fun MaxIntrinsicHeightMeasureBlock(orientation: LayoutOrientation) =
314 if (orientation == Horizontal) {
315 IntrinsicMeasureBlocks.HorizontalMaxHeight
316 } else {
317 IntrinsicMeasureBlocks.VerticalMaxHeight
318 }
319
320 internal object IntrinsicMeasureBlocks {
321 val HorizontalMinWidth: (List<IntrinsicMeasurable>, Int, Int) -> Int =
mainAxisSpacingnull322 { measurables, availableHeight, mainAxisSpacing ->
323 intrinsicSize(
324 measurables,
325 { h -> minIntrinsicWidth(h) },
326 { w -> maxIntrinsicHeight(w) },
327 availableHeight,
328 mainAxisSpacing,
329 Horizontal,
330 Horizontal
331 )
332 }
333 val VerticalMinWidth: (List<IntrinsicMeasurable>, Int, Int) -> Int =
mainAxisSpacingnull334 { measurables, availableHeight, mainAxisSpacing ->
335 intrinsicSize(
336 measurables,
337 { h -> minIntrinsicWidth(h) },
338 { w -> maxIntrinsicHeight(w) },
339 availableHeight,
340 mainAxisSpacing,
341 Vertical,
342 Horizontal
343 )
344 }
345 val HorizontalMinHeight: (List<IntrinsicMeasurable>, Int, Int) -> Int =
mainAxisSpacingnull346 { measurables, availableWidth, mainAxisSpacing ->
347 intrinsicSize(
348 measurables,
349 { w -> minIntrinsicHeight(w) },
350 { h -> maxIntrinsicWidth(h) },
351 availableWidth,
352 mainAxisSpacing,
353 Horizontal,
354 Vertical
355 )
356 }
357 val VerticalMinHeight: (List<IntrinsicMeasurable>, Int, Int) -> Int =
mainAxisSpacingnull358 { measurables, availableWidth, mainAxisSpacing ->
359 intrinsicSize(
360 measurables,
361 { w -> minIntrinsicHeight(w) },
362 { h -> maxIntrinsicWidth(h) },
363 availableWidth,
364 mainAxisSpacing,
365 Vertical,
366 Vertical
367 )
368 }
369 val HorizontalMaxWidth: (List<IntrinsicMeasurable>, Int, Int) -> Int =
mainAxisSpacingnull370 { measurables, availableHeight, mainAxisSpacing ->
371 intrinsicSize(
372 measurables,
373 { h -> maxIntrinsicWidth(h) },
374 { w -> maxIntrinsicHeight(w) },
375 availableHeight,
376 mainAxisSpacing,
377 Horizontal,
378 Horizontal
379 )
380 }
381 val VerticalMaxWidth: (List<IntrinsicMeasurable>, Int, Int) -> Int =
mainAxisSpacingnull382 { measurables, availableHeight, mainAxisSpacing ->
383 intrinsicSize(
384 measurables,
385 { h -> maxIntrinsicWidth(h) },
386 { w -> maxIntrinsicHeight(w) },
387 availableHeight,
388 mainAxisSpacing,
389 Vertical,
390 Horizontal
391 )
392 }
393 val HorizontalMaxHeight: (List<IntrinsicMeasurable>, Int, Int) -> Int =
mainAxisSpacingnull394 { measurables, availableWidth, mainAxisSpacing ->
395 intrinsicSize(
396 measurables,
397 { w -> maxIntrinsicHeight(w) },
398 { h -> maxIntrinsicWidth(h) },
399 availableWidth,
400 mainAxisSpacing,
401 Horizontal,
402 Vertical
403 )
404 }
405 val VerticalMaxHeight: (List<IntrinsicMeasurable>, Int, Int) -> Int =
mainAxisSpacingnull406 { measurables, availableWidth, mainAxisSpacing ->
407 intrinsicSize(
408 measurables,
409 { w -> maxIntrinsicHeight(w) },
410 { h -> maxIntrinsicWidth(h) },
411 availableWidth,
412 mainAxisSpacing,
413 Vertical,
414 Vertical
415 )
416 }
417 }
418
intrinsicSizenull419 private fun intrinsicSize(
420 children: List<IntrinsicMeasurable>,
421 intrinsicMainSize: IntrinsicMeasurable.(Int) -> Int,
422 intrinsicCrossSize: IntrinsicMeasurable.(Int) -> Int,
423 crossAxisAvailable: Int,
424 mainAxisSpacing: Int,
425 layoutOrientation: LayoutOrientation,
426 intrinsicOrientation: LayoutOrientation
427 ) = if (layoutOrientation == intrinsicOrientation) {
428 intrinsicMainAxisSize(children, intrinsicMainSize, crossAxisAvailable, mainAxisSpacing)
429 } else {
430 intrinsicCrossAxisSize(
431 children,
432 intrinsicCrossSize,
433 intrinsicMainSize,
434 crossAxisAvailable,
435 mainAxisSpacing
436 )
437 }
438
intrinsicMainAxisSizenull439 private fun intrinsicMainAxisSize(
440 children: List<IntrinsicMeasurable>,
441 mainAxisSize: IntrinsicMeasurable.(Int) -> Int,
442 crossAxisAvailable: Int,
443 mainAxisSpacing: Int
444 ): Int {
445 var weightUnitSpace = 0
446 var fixedSpace = 0
447 var totalWeight = 0f
448 children.fastForEach { child ->
449 val weight = child.rowColumnParentData.weight
450 val size = child.mainAxisSize(crossAxisAvailable)
451 if (weight == 0f) {
452 fixedSpace += size
453 } else if (weight > 0f) {
454 totalWeight += weight
455 weightUnitSpace = max(weightUnitSpace, (size / weight).roundToInt())
456 }
457 }
458 return (weightUnitSpace * totalWeight).roundToInt() + fixedSpace +
459 (children.size - 1) * mainAxisSpacing
460 }
461
intrinsicCrossAxisSizenull462 private fun intrinsicCrossAxisSize(
463 children: List<IntrinsicMeasurable>,
464 mainAxisSize: IntrinsicMeasurable.(Int) -> Int,
465 crossAxisSize: IntrinsicMeasurable.(Int) -> Int,
466 mainAxisAvailable: Int,
467 mainAxisSpacing: Int
468 ): Int {
469 var fixedSpace = min((children.size - 1) * mainAxisSpacing, mainAxisAvailable)
470 var crossAxisMax = 0
471 var totalWeight = 0f
472 children.fastForEach { child ->
473 val weight = child.rowColumnParentData.weight
474 if (weight == 0f) {
475 // Ask the child how much main axis space it wants to occupy. This cannot be more
476 // than the remaining available space.
477 val mainAxisSpace = min(
478 child.mainAxisSize(Constraints.Infinity),
479 mainAxisAvailable - fixedSpace
480 )
481 fixedSpace += mainAxisSpace
482 // Now that the assigned main axis space is known, ask about the cross axis space.
483 crossAxisMax = max(crossAxisMax, child.crossAxisSize(mainAxisSpace))
484 } else if (weight > 0f) {
485 totalWeight += weight
486 }
487 }
488
489 // For weighted children, calculate how much main axis space weight=1 would represent.
490 val weightUnitSpace = if (totalWeight == 0f) {
491 0
492 } else if (mainAxisAvailable == Constraints.Infinity) {
493 Constraints.Infinity
494 } else {
495 (max(mainAxisAvailable - fixedSpace, 0) / totalWeight).roundToInt()
496 }
497
498 children.fastForEach { child ->
499 val weight = child.rowColumnParentData.weight
500 // Now the main axis for weighted children is known, so ask about the cross axis space.
501 if (weight > 0f) {
502 crossAxisMax = max(
503 crossAxisMax,
504 child.crossAxisSize(
505 if (weightUnitSpace != Constraints.Infinity) {
506 (weightUnitSpace * weight).roundToInt()
507 } else {
508 Constraints.Infinity
509 }
510 )
511 )
512 }
513 }
514 return crossAxisMax
515 }
516
517 internal class LayoutWeightImpl(
518 val weight: Float,
519 val fill: Boolean,
520 inspectorInfo: InspectorInfo.() -> Unit
521 ) : ParentDataModifier, InspectorValueInfo(inspectorInfo) {
modifyParentDatanull522 override fun Density.modifyParentData(parentData: Any?) =
523 ((parentData as? RowColumnParentData) ?: RowColumnParentData()).also {
524 it.weight = weight
525 it.fill = fill
526 }
527
equalsnull528 override fun equals(other: Any?): Boolean {
529 if (this === other) return true
530 val otherModifier = other as? LayoutWeightImpl ?: return false
531 return weight == otherModifier.weight &&
532 fill == otherModifier.fill
533 }
534
hashCodenull535 override fun hashCode(): Int {
536 var result = weight.hashCode()
537 result = 31 * result + fill.hashCode()
538 return result
539 }
540
toStringnull541 override fun toString(): String =
542 "LayoutWeightImpl(weight=$weight, fill=$fill)"
543 }
544
545 internal sealed class SiblingsAlignedModifier(
546 inspectorInfo: InspectorInfo.() -> Unit
547 ) : ParentDataModifier, InspectorValueInfo(inspectorInfo) {
548 abstract override fun Density.modifyParentData(parentData: Any?): Any?
549
550 internal class WithAlignmentLineBlock(
551 val block: (Measured) -> Int,
552 inspectorInfo: InspectorInfo.() -> Unit
553 ) : SiblingsAlignedModifier(inspectorInfo) {
554 override fun Density.modifyParentData(parentData: Any?): Any {
555 return ((parentData as? RowColumnParentData) ?: RowColumnParentData()).also {
556 it.crossAxisAlignment =
557 CrossAxisAlignment.Relative(AlignmentLineProvider.Block(block))
558 }
559 }
560
561 override fun equals(other: Any?): Boolean {
562 if (this === other) return true
563 val otherModifier = other as? WithAlignmentLineBlock ?: return false
564 return block == otherModifier.block
565 }
566
567 override fun hashCode(): Int = block.hashCode()
568
569 override fun toString(): String = "WithAlignmentLineBlock(block=$block)"
570 }
571
572 internal class WithAlignmentLine(
573 val alignmentLine: AlignmentLine,
574 inspectorInfo: InspectorInfo.() -> Unit
575 ) : SiblingsAlignedModifier(inspectorInfo) {
576 override fun Density.modifyParentData(parentData: Any?): Any {
577 return ((parentData as? RowColumnParentData) ?: RowColumnParentData()).also {
578 it.crossAxisAlignment =
579 CrossAxisAlignment.Relative(AlignmentLineProvider.Value(alignmentLine))
580 }
581 }
582
583 override fun equals(other: Any?): Boolean {
584 if (this === other) return true
585 val otherModifier = other as? WithAlignmentLine ?: return false
586 return alignmentLine == otherModifier.alignmentLine
587 }
588
589 override fun hashCode(): Int = alignmentLine.hashCode()
590
591 override fun toString(): String = "WithAlignmentLine(line=$alignmentLine)"
592 }
593 }
594
595 internal class HorizontalAlignModifier(
596 val horizontal: Alignment.Horizontal,
597 inspectorInfo: InspectorInfo.() -> Unit
598 ) : ParentDataModifier, InspectorValueInfo(inspectorInfo) {
modifyParentDatanull599 override fun Density.modifyParentData(parentData: Any?): RowColumnParentData {
600 return ((parentData as? RowColumnParentData) ?: RowColumnParentData()).also {
601 it.crossAxisAlignment = CrossAxisAlignment.horizontal(horizontal)
602 }
603 }
604
equalsnull605 override fun equals(other: Any?): Boolean {
606 if (this === other) return true
607 val otherModifier = other as? HorizontalAlignModifier ?: return false
608 return horizontal == otherModifier.horizontal
609 }
610
hashCodenull611 override fun hashCode(): Int = horizontal.hashCode()
612
613 override fun toString(): String =
614 "HorizontalAlignModifier(horizontal=$horizontal)"
615 }
616
617 internal class VerticalAlignModifier(
618 val vertical: Alignment.Vertical,
619 inspectorInfo: InspectorInfo.() -> Unit
620 ) : ParentDataModifier, InspectorValueInfo(inspectorInfo) {
621 override fun Density.modifyParentData(parentData: Any?): RowColumnParentData {
622 return ((parentData as? RowColumnParentData) ?: RowColumnParentData()).also {
623 it.crossAxisAlignment = CrossAxisAlignment.vertical(vertical)
624 }
625 }
626
627 override fun equals(other: Any?): Boolean {
628 if (this === other) return true
629 val otherModifier = other as? VerticalAlignModifier ?: return false
630 return vertical == otherModifier.vertical
631 }
632
633 override fun hashCode(): Int = vertical.hashCode()
634
635 override fun toString(): String =
636 "VerticalAlignModifier(vertical=$vertical)"
637 }
638
639 /**
640 * Provides the alignment line.
641 */
642 internal sealed class AlignmentLineProvider {
calculateAlignmentLinePositionnull643 abstract fun calculateAlignmentLinePosition(placeable: Placeable): Int
644 data class Block(val lineProviderBlock: (Measured) -> Int) : AlignmentLineProvider() {
645 override fun calculateAlignmentLinePosition(
646 placeable: Placeable
647 ): Int {
648 return lineProviderBlock(placeable)
649 }
650 }
651
652 data class Value(val alignmentLine: AlignmentLine) : AlignmentLineProvider() {
calculateAlignmentLinePositionnull653 override fun calculateAlignmentLinePosition(placeable: Placeable): Int {
654 return placeable[alignmentLine]
655 }
656 }
657 }
658
659 /**
660 * Used to specify how a layout chooses its own size when multiple behaviors are possible.
661 */
662 // TODO(popam): remove this when Flow is reworked
663 internal enum class SizeMode {
664 /**
665 * Minimize the amount of free space by wrapping the children,
666 * subject to the incoming layout constraints.
667 */
668 Wrap,
669
670 /**
671 * Maximize the amount of free space by expanding to fill the available space,
672 * subject to the incoming layout constraints.
673 */
674 Expand
675 }
676