1 /* 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 17 package androidx.compose.foundation.shape 18 19 import androidx.compose.foundation.internal.requirePrecondition 20 import androidx.compose.ui.geometry.Size 21 import androidx.compose.ui.graphics.Outline 22 import androidx.compose.ui.graphics.Shape 23 import androidx.compose.ui.unit.Density 24 import androidx.compose.ui.unit.LayoutDirection 25 26 /** 27 * Base class for [Shape]s defined by four [CornerSize]s. 28 * 29 * @param topStart a size of the top start corner 30 * @param topEnd a size of the top end corner 31 * @param bottomEnd a size of the bottom end corner 32 * @param bottomStart a size of the bottom start corner 33 * @see RoundedCornerShape for an example of the usage. 34 */ 35 abstract class CornerBasedShape( 36 val topStart: CornerSize, 37 val topEnd: CornerSize, 38 val bottomEnd: CornerSize, 39 val bottomStart: CornerSize 40 ) : Shape { 41 createOutlinenull42 final override fun createOutline( 43 size: Size, 44 layoutDirection: LayoutDirection, 45 density: Density 46 ): Outline { 47 var topStart = topStart.toPx(size, density) 48 var topEnd = topEnd.toPx(size, density) 49 var bottomEnd = bottomEnd.toPx(size, density) 50 var bottomStart = bottomStart.toPx(size, density) 51 val minDimension = size.minDimension 52 if (topStart + bottomStart > minDimension) { 53 val scale = minDimension / (topStart + bottomStart) 54 topStart *= scale 55 bottomStart *= scale 56 } 57 if (topEnd + bottomEnd > minDimension) { 58 val scale = minDimension / (topEnd + bottomEnd) 59 topEnd *= scale 60 bottomEnd *= scale 61 } 62 requirePrecondition( 63 topStart >= 0.0f && topEnd >= 0.0f && bottomEnd >= 0.0f && bottomStart >= 0.0f 64 ) { 65 "Corner size in Px can't be negative(topStart = $topStart, topEnd = $topEnd, " + 66 "bottomEnd = $bottomEnd, bottomStart = $bottomStart)!" 67 } 68 return createOutline( 69 size = size, 70 topStart = topStart, 71 topEnd = topEnd, 72 bottomEnd = bottomEnd, 73 bottomStart = bottomStart, 74 layoutDirection = layoutDirection 75 ) 76 } 77 78 /** 79 * Creates [Outline] of this shape for the given [size]. 80 * 81 * @param size the size of the shape boundary. 82 * @param topStart the resolved size of the top start corner 83 * @param topEnd the resolved size for the top end corner 84 * @param bottomEnd the resolved size for the bottom end corner 85 * @param bottomStart the resolved size for the bottom start corner 86 * @param layoutDirection the current layout direction. 87 */ createOutlinenull88 abstract fun createOutline( 89 size: Size, 90 topStart: Float, 91 topEnd: Float, 92 bottomEnd: Float, 93 bottomStart: Float, 94 layoutDirection: LayoutDirection 95 ): Outline 96 97 /** 98 * Creates a copy of this Shape with a new corner sizes. 99 * 100 * @param topStart a size of the top start corner 101 * @param topEnd a size of the top end corner 102 * @param bottomEnd a size of the bottom end corner 103 * @param bottomStart a size of the bottom start corner 104 */ 105 abstract fun copy( 106 topStart: CornerSize = this.topStart, 107 topEnd: CornerSize = this.topEnd, 108 bottomEnd: CornerSize = this.bottomEnd, 109 bottomStart: CornerSize = this.bottomStart 110 ): CornerBasedShape 111 112 /** 113 * Creates a copy of this Shape with a new corner size. 114 * 115 * @param all a size to apply for all four corners 116 */ 117 fun copy(all: CornerSize): CornerBasedShape = copy(all, all, all, all) 118 } 119