[go: nahoru, domu]

blob: b94ad32bf453226e225f0b81a38f2b687428add0 [file] [log] [blame]
/*
* Copyright 2019 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.selection
import androidx.compose.Composable
import androidx.compose.remember
import androidx.ui.core.Constraints
import androidx.ui.core.Draw
import androidx.ui.core.Layout
import androidx.ui.geometry.Rect
import androidx.ui.graphics.Color
import androidx.ui.graphics.Paint
import androidx.ui.graphics.Path
import androidx.ui.text.style.TextDirection
import androidx.ui.unit.Dp
import androidx.ui.unit.dp
import androidx.ui.unit.ipx
internal val HANDLE_WIDTH = 25.dp
internal val HANDLE_HEIGHT = 25.dp
private val HANDLE_COLOR = Color(0xFF2B28F5.toInt())
@Composable
private fun SelectionHandle(left: Boolean) {
val paint = remember { Paint().also { it.isAntiAlias = true } }
paint.color = HANDLE_COLOR
FixedDimension(width = HANDLE_WIDTH, height = HANDLE_HEIGHT) {
Draw { canvas, _ ->
val path = Path().apply {
addRect(
Rect(
top = 0f,
bottom = 0.5f * HANDLE_HEIGHT.toPx().value,
left = if (left) {
0.5f * HANDLE_WIDTH.toPx().value
} else {
0f
},
right = if (left) {
HANDLE_WIDTH.toPx().value
} else {
0.5f * HANDLE_WIDTH.toPx().value
}
)
)
addOval(
Rect(
top = 0f,
bottom = HANDLE_HEIGHT.toPx().value,
left = 0f,
right = HANDLE_WIDTH.toPx().value
)
)
}
canvas.drawPath(path, paint)
}
}
}
@Composable
private fun FixedDimension(
width: Dp,
height: Dp,
children: @Composable() () -> Unit
) {
Layout(children) { measurables, _ ->
val constraints = Constraints.fixed(width.toIntPx(), height.toIntPx())
val placeables = measurables.map { measurable ->
measurable.measure(constraints)
}
layout(width.toIntPx(), height.toIntPx()) {
placeables.forEach { placeable ->
placeable.place(0.ipx, 0.ipx)
}
}
}
}
@Composable
internal fun StartSelectionHandle(selection: Selection?) {
selection?.let {
if (isHandleLtrDirection(it.start.direction, it.handlesCrossed)) {
SelectionHandle(left = true)
} else {
SelectionHandle(left = false)
}
}
}
@Composable
internal fun EndSelectionHandle(selection: Selection?) {
selection?.let {
if (isHandleLtrDirection(it.end.direction, it.handlesCrossed)) {
SelectionHandle(left = false)
} else {
SelectionHandle(left = true)
}
}
}
/**
* This method is to check if the selection handles should use the natural Ltr pointing
* direction.
* If the context is Ltr and the handles are not crossed, or if the context is Rtl and the handles
* are crossed, return true.
*
* In Ltr context, the start handle should point to the left, and the end handle should point to
* the right. However, in Rtl context or when handles are crossed, the start handle should point to
* the right, and the end handle should point to left.
*/
internal fun isHandleLtrDirection(direction: TextDirection, areHandlesCrossed: Boolean): Boolean {
return direction == TextDirection.Ltr && !areHandlesCrossed ||
direction == TextDirection.Rtl && areHandlesCrossed
}