[go: nahoru, domu]

blob: 85aeed4acdc8430cd909a6672fe770428cad01c7 [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.emptyContent
import androidx.compose.remember
import androidx.ui.core.Layout
import androidx.ui.core.Modifier
import androidx.ui.core.DrawScope
import androidx.ui.core.drawBehind
import androidx.ui.geometry.Rect
import androidx.ui.graphics.Color
import androidx.ui.graphics.Paint
import androidx.ui.graphics.Path
import androidx.ui.graphics.painter.drawCanvas
import androidx.ui.text.style.TextDirection
import androidx.ui.unit.Dp
import androidx.ui.unit.dp
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
HandleDrawLayout(width = HANDLE_WIDTH, height = HANDLE_HEIGHT) {
drawCanvas { 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)
}
}
}
/**
* Simple container to perform drawing of selection handles. This layout takes size on the screen
* according to [width] and [height] params and performs drawing in this space as specified in
* [onCanvas]
*/
@Composable
private fun HandleDrawLayout(
width: Dp,
height: Dp,
onCanvas: DrawScope.() -> Unit
) {
Layout(emptyContent(), Modifier.drawBehind(onCanvas)) { _, _, _ ->
// take width and height space of the screen and allow draw modifier to draw inside of it
layout(width.toIntPx(), height.toIntPx()) {
// this layout has no children, only draw modifier.
}
}
}
@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
}