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.annotation.FloatRange
20 import androidx.annotation.IntRange
21 import androidx.compose.foundation.internal.throwIllegalArgumentException
22 import androidx.compose.runtime.Immutable
23 import androidx.compose.runtime.Stable
24 import androidx.compose.ui.geometry.Size
25 import androidx.compose.ui.platform.InspectableValue
26 import androidx.compose.ui.unit.Density
27 import androidx.compose.ui.unit.Dp
28
29 /** Defines size of a corner in pixels. For example for rounded shape it can be a corner radius. */
30 @Immutable
31 interface CornerSize {
32 /**
33 * Converts the [CornerSize] to pixels.
34 *
35 * @param shapeSize the size of the shape
36 * @param density the current density of the screen.
37 * @return resolved size of the corner in pixels
38 */
toPxnull39 fun toPx(shapeSize: Size, density: Density): Float
40 }
41
42 /**
43 * Creates [CornerSize] with provided size.
44 *
45 * @param size the corner size defined in [Dp].
46 */
47 @Stable fun CornerSize(size: Dp): CornerSize = DpCornerSize(size)
48
49 private data class DpCornerSize(private val size: Dp) : CornerSize, InspectableValue {
50 override fun toPx(shapeSize: Size, density: Density) = with(density) { size.toPx() }
51
52 override fun toString(): String = "CornerSize(size = ${size.value}.dp)"
53
54 override val valueOverride: Dp
55 get() = size
56 }
57
58 /**
59 * Creates [CornerSize] with provided size.
60 *
61 * @param size the corner size defined in pixels.
62 */
CornerSizenull63 @Stable fun CornerSize(size: Float): CornerSize = PxCornerSize(size)
64
65 private data class PxCornerSize(private val size: Float) : CornerSize, InspectableValue {
66 override fun toPx(shapeSize: Size, density: Density) = size
67
68 override fun toString(): String = "CornerSize(size = $size.px)"
69
70 override val valueOverride: String
71 get() = "${size}px"
72 }
73
74 /**
75 * Creates [CornerSize] with provided size.
76 *
77 * @param percent the corner size defined in percents of the shape's smaller side. Can't be negative
78 * or larger then 100 percents.
79 */
80 @Stable
CornerSizenull81 fun CornerSize(@IntRange(from = 0, to = 100) percent: Int): CornerSize =
82 PercentCornerSize(percent.toFloat())
83
84 /**
85 * Creates [CornerSize] with provided size.
86 *
87 * @param percent the corner size defined in float percents of the shape's smaller side. Can't be
88 * negative or larger then 100 percents.
89 */
90 private data class PercentCornerSize(
91 @FloatRange(from = 0.0, to = 100.0) private val percent: Float
92 ) : CornerSize, InspectableValue {
93 init {
94 if (percent < 0 || percent > 100) {
95 throwIllegalArgumentException("The percent should be in the range of [0, 100]")
96 }
97 }
98
99 override fun toPx(shapeSize: Size, density: Density) = shapeSize.minDimension * (percent / 100f)
100
101 override fun toString(): String = "CornerSize(size = $percent%)"
102
103 override val valueOverride: String
104 get() = "$percent%"
105 }
106
107 /** [CornerSize] always equals to zero. */
108 @Stable
109 val ZeroCornerSize: CornerSize =
110 object : CornerSize, InspectableValue {
toPxnull111 override fun toPx(shapeSize: Size, density: Density) = 0.0f
112
113 override fun toString(): String = "ZeroCornerSize"
114
115 override val valueOverride: String
116 get() = "ZeroCornerSize"
117 }
118