[go: nahoru, domu]

blob: af8bb3640d21afea00f5cc1d649ac428bcfe8c1c [file] [log] [blame]
Andrey Kulikovb33a3802020-05-21 20:02:53 +01001/*
2 * Copyright 2020 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 * http://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
17package androidx.ui.core
18
19import androidx.ui.core.LayoutNode.LayoutState
20import androidx.ui.core.LayoutNode.MeasureBlocks
21import androidx.ui.core.LayoutNode.UsageByParent
George Mount8f237572020-04-30 12:08:30 -070022import androidx.ui.unit.IntOffset
23import androidx.ui.unit.IntSize
Andrey Kulikovb33a3802020-05-21 20:02:53 +010024
George Mount5469e252020-06-17 10:01:42 -070025@OptIn(ExperimentalLayoutNodeApi::class)
Andrey Kulikovb33a3802020-05-21 20:02:53 +010026internal class OuterMeasurablePlaceable(
27 private val layoutNode: LayoutNode,
28 var outerWrapper: LayoutNodeWrapper
29) : Measurable, Placeable() {
30
31 private var measuredOnce = false
32 val lastConstraints: Constraints? get() = if (measuredOnce) measurementConstraints else null
33 var lastLayoutDirection: LayoutDirection? = null
34 private set
George Mount8f237572020-04-30 12:08:30 -070035 var lastPosition: IntOffset? = null
Andrey Kulikovb33a3802020-05-21 20:02:53 +010036 private set
George Mount8f237572020-04-30 12:08:30 -070037 private val lastProvidedAlignmentLines = mutableMapOf<AlignmentLine, Int>()
Andrey Kulikovb33a3802020-05-21 20:02:53 +010038
39 /**
40 * A local version of [Owner.measureIteration] to ensure that [MeasureBlocks.measure]
41 * is not called multiple times within a measure pass.
42 */
43 var measureIteration = -1L
44 private set
45
46 override val parentData: Any? get() = outerWrapper.parentData
47
48 /**
49 * The function to be executed when the parent layout measures its children.
50 */
51 override fun measure(constraints: Constraints, layoutDirection: LayoutDirection): Placeable {
52 // when we measure the root it is like the virtual parent is currently laying out
53 val parentState = layoutNode.parent?.layoutState ?: LayoutState.LayingOut
54 layoutNode.measuredByParent = when (parentState) {
55 LayoutState.Measuring -> UsageByParent.InMeasureBlock
56 LayoutState.LayingOut -> UsageByParent.InLayoutBlock
57 else -> throw IllegalStateException(
58 "Measurable could be only measured from the parent's measure or layout block." +
59 "Parents state is $parentState"
60 )
61 }
62 remeasure(constraints, layoutDirection)
63 return this
64 }
65
66 /**
67 * Return true if the measured size has been changed
68 */
69 fun remeasure(constraints: Constraints, layoutDirection: LayoutDirection): Boolean {
70 val owner = layoutNode.requireOwner()
71 val iteration = owner.measureIteration
72 val parent = layoutNode.parent
73 @Suppress("Deprecation")
74 layoutNode.canMultiMeasure = layoutNode.canMultiMeasure ||
75 (parent != null && parent.canMultiMeasure)
76 @Suppress("Deprecation")
77 check(measureIteration != iteration || layoutNode.canMultiMeasure) {
78 "measure() may not be called multiple times on the same Measurable"
79 }
80 measureIteration = owner.measureIteration
81 if (layoutNode.layoutState == LayoutState.NeedsRemeasure ||
82 measurementConstraints != constraints ||
83 lastLayoutDirection != layoutDirection
84 ) {
85 measuredOnce = true
86 layoutNode.layoutState = LayoutState.Measuring
87 measurementConstraints = constraints
88 lastLayoutDirection = layoutDirection
89 lastProvidedAlignmentLines.clear()
90 lastProvidedAlignmentLines.putAll(layoutNode.providedAlignmentLines)
91 owner.observeMeasureModelReads(layoutNode) {
92 outerWrapper.measure(constraints, layoutDirection)
93 }
94 layoutNode.layoutState = LayoutState.NeedsRelayout
95 if (layoutNode.providedAlignmentLines != lastProvidedAlignmentLines) {
96 layoutNode.onAlignmentsChanged()
97 }
98 val previousSize = measuredSize
99 val newWidth = outerWrapper.width
100 val newHeight = outerWrapper.height
101 if (newWidth != previousSize.width ||
102 newHeight != previousSize.height
103 ) {
George Mount8f237572020-04-30 12:08:30 -0700104 measuredSize = IntSize(newWidth, newHeight)
Andrey Kulikovb33a3802020-05-21 20:02:53 +0100105 return true
106 }
107 }
108 return false
109 }
110
Mihai Popa08c47952020-06-04 20:01:27 +0100111 override fun get(line: AlignmentLine): Int = outerWrapper[line]
Andrey Kulikovb33a3802020-05-21 20:02:53 +0100112
George Mount8f237572020-04-30 12:08:30 -0700113 override fun place(position: IntOffset) {
Andrey Kulikovb33a3802020-05-21 20:02:53 +0100114 lastPosition = position
115 with(InnerPlacementScope) {
116 outerWrapper.placeAbsolute(position)
117 }
118 }
119
120 /**
121 * Calls [place] with the same position used during the last [place] call
122 */
123 fun replace() {
124 place(checkNotNull(lastPosition))
125 }
126
George Mount8f237572020-04-30 12:08:30 -0700127 override fun minIntrinsicWidth(height: Int, layoutDirection: LayoutDirection): Int =
Andrey Kulikovb33a3802020-05-21 20:02:53 +0100128 outerWrapper.minIntrinsicWidth(height, layoutDirection)
129
George Mount8f237572020-04-30 12:08:30 -0700130 override fun maxIntrinsicWidth(height: Int, layoutDirection: LayoutDirection): Int =
Andrey Kulikovb33a3802020-05-21 20:02:53 +0100131 outerWrapper.maxIntrinsicWidth(height, layoutDirection)
132
George Mount8f237572020-04-30 12:08:30 -0700133 override fun minIntrinsicHeight(width: Int, layoutDirection: LayoutDirection): Int =
Andrey Kulikovb33a3802020-05-21 20:02:53 +0100134 outerWrapper.minIntrinsicHeight(width, layoutDirection)
135
George Mount8f237572020-04-30 12:08:30 -0700136 override fun maxIntrinsicHeight(width: Int, layoutDirection: LayoutDirection): Int =
Andrey Kulikovb33a3802020-05-21 20:02:53 +0100137 outerWrapper.maxIntrinsicHeight(width, layoutDirection)
138}