1 /*
2  * Copyright 2021 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.IntRange
20 import androidx.compose.ui.geometry.CornerRadius
21 import androidx.compose.ui.geometry.RoundRect
22 import androidx.compose.ui.geometry.Size
23 import androidx.compose.ui.geometry.toRect
24 import androidx.compose.ui.graphics.Outline
25 import androidx.compose.ui.unit.Dp
26 import androidx.compose.ui.unit.LayoutDirection
27 import androidx.compose.ui.unit.dp
28 
29 /**
30  * A shape describing the rectangle with rounded corners.
31  *
32  * This shape will not automatically mirror the corner sizes in [LayoutDirection.Rtl], use
33  * [RoundedCornerShape] for the layout direction aware version of this shape.
34  *
35  * @param topLeft a size of the top left corner
36  * @param topRight a size of the top right corner
37  * @param bottomRight a size of the bottom right corner
38  * @param bottomLeft a size of the bottom left corner
39  */
40 class AbsoluteRoundedCornerShape(
41     topLeft: CornerSize,
42     topRight: CornerSize,
43     bottomRight: CornerSize,
44     bottomLeft: CornerSize
45 ) :
46     CornerBasedShape(
47         topStart = topLeft,
48         topEnd = topRight,
49         bottomEnd = bottomRight,
50         bottomStart = bottomLeft
51     ) {
52 
createOutlinenull53     override fun createOutline(
54         size: Size,
55         topStart: Float,
56         topEnd: Float,
57         bottomEnd: Float,
58         bottomStart: Float,
59         layoutDirection: LayoutDirection
60     ) =
61         if (topStart + topEnd + bottomEnd + bottomStart == 0.0f) {
62             Outline.Rectangle(size.toRect())
63         } else {
64             Outline.Rounded(
65                 RoundRect(
66                     rect = size.toRect(),
67                     topLeft = CornerRadius(topStart),
68                     topRight = CornerRadius(topEnd),
69                     bottomRight = CornerRadius(bottomEnd),
70                     bottomLeft = CornerRadius(bottomStart)
71                 )
72             )
73         }
74 
copynull75     override fun copy(
76         topStart: CornerSize,
77         topEnd: CornerSize,
78         bottomEnd: CornerSize,
79         bottomStart: CornerSize
80     ) =
81         AbsoluteRoundedCornerShape(
82             topLeft = topStart,
83             topRight = topEnd,
84             bottomRight = bottomEnd,
85             bottomLeft = bottomStart
86         )
87 
88     override fun toString(): String {
89         return "AbsoluteRoundedCornerShape(topLeft = $topStart, topRight = $topEnd, " +
90             "bottomRight = $bottomEnd, bottomLeft = $bottomStart)"
91     }
92 
equalsnull93     override fun equals(other: Any?): Boolean {
94         if (this === other) return true
95         if (other !is AbsoluteRoundedCornerShape) return false
96 
97         if (topStart != other.topStart) return false
98         if (topEnd != other.topEnd) return false
99         if (bottomEnd != other.bottomEnd) return false
100         if (bottomStart != other.bottomStart) return false
101 
102         return true
103     }
104 
hashCodenull105     override fun hashCode(): Int {
106         var result = topStart.hashCode()
107         result = 31 * result + topEnd.hashCode()
108         result = 31 * result + bottomEnd.hashCode()
109         result = 31 * result + bottomStart.hashCode()
110         return result
111     }
112 
Floatnull113     private fun Float.toRadius() = CornerRadius(this)
114 }
115 
116 /**
117  * Creates [AbsoluteRoundedCornerShape] with the same size applied for all four corners.
118  *
119  * @param corner [CornerSize] to apply.
120  */
121 fun AbsoluteRoundedCornerShape(corner: CornerSize) =
122     AbsoluteRoundedCornerShape(corner, corner, corner, corner)
123 
124 /**
125  * Creates [AbsoluteRoundedCornerShape] with the same size applied for all four corners.
126  *
127  * @param size Size in [Dp] to apply.
128  */
129 fun AbsoluteRoundedCornerShape(size: Dp) = AbsoluteRoundedCornerShape(CornerSize(size))
130 
131 /**
132  * Creates [AbsoluteRoundedCornerShape] with the same size applied for all four corners.
133  *
134  * @param size Size in pixels to apply.
135  */
136 fun AbsoluteRoundedCornerShape(size: Float) = AbsoluteRoundedCornerShape(CornerSize(size))
137 
138 /**
139  * Creates [AbsoluteRoundedCornerShape] with the same size applied for all four corners.
140  *
141  * @param percent Size in percents to apply.
142  */
143 fun AbsoluteRoundedCornerShape(percent: Int) = AbsoluteRoundedCornerShape(CornerSize(percent))
144 
145 /** Creates [AbsoluteRoundedCornerShape] with sizes defined in [Dp]. */
146 fun AbsoluteRoundedCornerShape(
147     topLeft: Dp = 0.dp,
148     topRight: Dp = 0.dp,
149     bottomRight: Dp = 0.dp,
150     bottomLeft: Dp = 0.dp
151 ) =
152     AbsoluteRoundedCornerShape(
153         topLeft = CornerSize(topLeft),
154         topRight = CornerSize(topRight),
155         bottomRight = CornerSize(bottomRight),
156         bottomLeft = CornerSize(bottomLeft)
157     )
158 
159 /** Creates [AbsoluteRoundedCornerShape] with sizes defined in pixels. */
160 fun AbsoluteRoundedCornerShape(
161     topLeft: Float = 0.0f,
162     topRight: Float = 0.0f,
163     bottomRight: Float = 0.0f,
164     bottomLeft: Float = 0.0f
165 ) =
166     AbsoluteRoundedCornerShape(
167         topLeft = CornerSize(topLeft),
168         topRight = CornerSize(topRight),
169         bottomRight = CornerSize(bottomRight),
170         bottomLeft = CornerSize(bottomLeft)
171     )
172 
173 /**
174  * Creates [AbsoluteRoundedCornerShape] with sizes defined in percents of the shape's smaller side.
175  *
176  * @param topLeftPercent The top left corner radius as a percentage of the smaller side, with a
177  *   range of 0 - 100.
178  * @param topRightPercent The top right corner radius as a percentage of the smaller side, with a
179  *   range of 0 - 100.
180  * @param bottomRightPercent The bottom right corner radius as a percentage of the smaller side,
181  *   with a range of 0 - 100.
182  * @param bottomLeftPercent The bottom left corner radius as a percentage of the smaller side, with
183  *   a range of 0 - 100.
184  */
185 fun AbsoluteRoundedCornerShape(
186     @IntRange(from = 0, to = 100) topLeftPercent: Int = 0,
187     @IntRange(from = 0, to = 100) topRightPercent: Int = 0,
188     @IntRange(from = 0, to = 100) bottomRightPercent: Int = 0,
189     @IntRange(from = 0, to = 100) bottomLeftPercent: Int = 0
190 ) =
191     AbsoluteRoundedCornerShape(
192         topLeft = CornerSize(topLeftPercent),
193         topRight = CornerSize(topRightPercent),
194         bottomRight = CornerSize(bottomRightPercent),
195         bottomLeft = CornerSize(bottomLeftPercent)
196     )
197