[go: nahoru, domu]

blob: 782ec0ef3a85913bd990e1c8ba40b7201d1ea087 [file] [log] [blame]
/*
* Copyright 2020 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.ui.core
import androidx.ui.core.focus.ExperimentalFocus
import androidx.ui.core.focus.FocusState2
import androidx.ui.core.focus.ModifiedFocusNode
import androidx.ui.core.focus.ModifiedFocusNode2
import androidx.ui.core.keyinput.ModifiedKeyInputNode
import androidx.ui.core.pointerinput.PointerInputFilter
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Canvas
import androidx.ui.unit.IntOffset
import androidx.ui.util.nativeClass
/**
* [LayoutNodeWrapper] with default implementations for methods.
*/
@OptIn(ExperimentalLayoutNodeApi::class)
internal open class DelegatingLayoutNodeWrapper<T : Modifier.Element>(
override var wrapped: LayoutNodeWrapper,
open var modifier: T
) : LayoutNodeWrapper(wrapped.layoutNode) {
override val providedAlignmentLines: Set<AlignmentLine>
get() = wrapped.providedAlignmentLines
private var _isAttached = true
override val isAttached: Boolean
get() = _isAttached && layoutNode.isAttached()
override val measureScope: MeasureScope get() = wrapped.measureScope
/**
* Indicates that this modifier is used in [wrappedBy] also.
*/
var isChained = false
init {
wrapped.wrappedBy = this
}
/**
* Sets the modifier instance to the new modifier. [modifier] must be the
* same type as the current modifier.
*/
fun setModifierTo(modifier: Modifier.Element) {
if (modifier !== this.modifier) {
require(modifier.nativeClass() == this.modifier.nativeClass())
@Suppress("UNCHECKED_CAST")
this.modifier = modifier as T
}
}
override fun draw(canvas: Canvas) {
withPositionTranslation(canvas) {
wrapped.draw(canvas)
}
}
override fun hitTest(
pointerPositionRelativeToScreen: Offset,
hitPointerInputFilters: MutableList<PointerInputFilter>
) {
wrapped.hitTest(pointerPositionRelativeToScreen, hitPointerInputFilters)
}
override fun get(line: AlignmentLine): Int = wrapped[line]
override fun place(position: IntOffset) {
this.position = position
// The wrapper only runs their placement block to obtain our position, which allows them
// to calculate the offset of an alignment line we have already provided a position for.
// No need to place our wrapped as well (we might have actually done this already in
// get(line), to obtain the position of the alignment line the wrapper currently needs
// our position in order ot know how to offset the value we provided).
if (wrappedBy?.isShallowPlacing == true) return
with(InnerPlacementScope) {
this.parentLayoutDirection = measureScope.layoutDirection
val previousParentWidth = parentWidth
parentWidth = measuredSize.width
measureResult.placeChildren(measureScope.layoutDirection)
parentWidth = previousParentWidth
}
}
override fun performMeasure(
constraints: Constraints,
layoutDirection: LayoutDirection
): Placeable {
val placeable = wrapped.measure(constraints, layoutDirection)
measureResult = object : MeasureScope.MeasureResult {
override val width: Int = wrapped.measureResult.width
override val height: Int = wrapped.measureResult.height
override val alignmentLines: Map<AlignmentLine, Int> = emptyMap()
override fun placeChildren(layoutDirection: LayoutDirection) {
with(InnerPlacementScope) {
placeable.placeAbsolute(-apparentToRealOffset)
}
}
}
return this
}
override fun findPreviousFocusWrapper() = wrappedBy?.findPreviousFocusWrapper()
override fun findPreviousFocusWrapper2() = wrappedBy?.findPreviousFocusWrapper2()
override fun findNextFocusWrapper() = wrapped.findNextFocusWrapper()
override fun findNextFocusWrapper2() = wrapped.findNextFocusWrapper2()
override fun findLastFocusWrapper(): ModifiedFocusNode? {
var lastFocusWrapper: ModifiedFocusNode? = null
// Find last focus wrapper for the current layout node.
var next: ModifiedFocusNode? = findNextFocusWrapper()
while (next != null) {
lastFocusWrapper = next
next = next.wrapped.findNextFocusWrapper()
}
return lastFocusWrapper
}
override fun findLastFocusWrapper2(): ModifiedFocusNode2? {
var lastFocusWrapper: ModifiedFocusNode2? = null
// Find last focus wrapper for the current layout node.
var next: ModifiedFocusNode2? = findNextFocusWrapper2()
while (next != null) {
lastFocusWrapper = next
next = next.wrapped.findNextFocusWrapper2()
}
return lastFocusWrapper
}
@OptIn(ExperimentalFocus::class)
override fun propagateFocusStateChange(focusState: FocusState2) {
wrappedBy?.propagateFocusStateChange(focusState)
}
override fun findPreviousKeyInputWrapper() = wrappedBy?.findPreviousKeyInputWrapper()
override fun findNextKeyInputWrapper() = wrapped.findNextKeyInputWrapper()
override fun findLastKeyInputWrapper(): ModifiedKeyInputNode? {
val wrapper = layoutNode.innerLayoutNodeWrapper.findPreviousKeyInputWrapper()
return if (wrapper !== this) wrapper else null
}
override fun minIntrinsicWidth(height: Int, layoutDirection: LayoutDirection) =
wrapped.minIntrinsicWidth(height, layoutDirection)
override fun maxIntrinsicWidth(height: Int, layoutDirection: LayoutDirection) =
wrapped.maxIntrinsicWidth(height, layoutDirection)
override fun minIntrinsicHeight(width: Int, layoutDirection: LayoutDirection) =
wrapped.minIntrinsicHeight(width, layoutDirection)
override fun maxIntrinsicHeight(width: Int, layoutDirection: LayoutDirection) =
wrapped.maxIntrinsicHeight(width, layoutDirection)
override val parentData: Any? get() = wrapped.parentData
override fun attach() {
_isAttached = true
}
override fun detach() {
_isAttached = false
}
}
internal object InnerPlacementScope : Placeable.PlacementScope() {
override var parentWidth = 0
override var parentLayoutDirection = LayoutDirection.Ltr
}