LayoutNodeAlignmentLines.kt
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.compose.ui.node
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.layout.AlignmentLine
import androidx.compose.ui.layout.HorizontalAlignmentLine
import androidx.compose.ui.layout.merge
import kotlin.math.roundToInt
internal class LayoutNodeAlignmentLines(
private val layoutNode: LayoutNode
) {
/**
* The alignment lines of this layout, inherited + intrinsic
*/
private val alignmentLines: MutableMap<AlignmentLine, Int> = hashMapOf()
private val previousAlignmentLines = mutableMapOf<AlignmentLine, Int>()
fun getLastCalculation(): Map<AlignmentLine, Int> = alignmentLines
fun recalculate() {
previousAlignmentLines.clear()
previousAlignmentLines.putAll(alignmentLines)
alignmentLines.clear()
layoutNode._children.forEach { child ->
val childAlignments = child.alignmentLines
if (!child.isPlaced || childAlignments == null) return@forEach
childAlignments.alignmentLines.keys.forEach { childLine ->
val linePositionInContainer = childAlignments.getAlignmentLine(childLine)!!
// If the line was already provided by a previous child, merge the values.
alignmentLines[childLine] = if (childLine in alignmentLines) {
childLine.merge(
alignmentLines.getValue(childLine),
linePositionInContainer
)
} else {
linePositionInContainer
}
}
}
alignmentLines += layoutNode.providedAlignmentLines
if (previousAlignmentLines != alignmentLines) {
layoutNode.onAlignmentsChanged()
}
}
/**
* Returns the alignment line value for a given alignment line without affecting whether
* the flag for whether the alignment line was read.
*/
private fun getAlignmentLine(alignmentLine: AlignmentLine): Int? {
val linePos = alignmentLines[alignmentLine] ?: return null
var pos = Offset(linePos.toFloat(), linePos.toFloat())
var wrapper = layoutNode.innerLayoutNodeWrapper
while (wrapper != layoutNode.outerLayoutNodeWrapper) {
pos = wrapper.toParentPosition(pos)
wrapper = wrapper.wrappedBy!!
}
pos = wrapper.toParentPosition(pos)
return if (alignmentLine is HorizontalAlignmentLine) {
pos.y.roundToInt()
} else {
pos.x.roundToInt()
}
}
}