1 /* 2 * Copyright (C) 2017 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 @file:Suppress("NOTHING_TO_INLINE") 18 19 package androidx.core.graphics 20 21 import android.annotation.SuppressLint 22 import android.graphics.Matrix 23 import android.graphics.Point 24 import android.graphics.PointF 25 import android.graphics.Rect 26 import android.graphics.RectF 27 import android.graphics.Region 28 29 /** 30 * Returns "left", the first component of the rectangle. 31 * 32 * This method allows to use destructuring declarations when working with rectangles, 33 * for example: 34 * ``` 35 * val (left, top, right, bottom) = myRectangle 36 * ``` 37 */ 38 inline operator fun Rect.component1() = this.left 39 40 /** 41 * Returns "top", the second component of the rectangle. 42 * 43 * This method allows to use destructuring declarations when working with rectangles, 44 * for example: 45 * ``` 46 * val (left, top, right, bottom) = myRectangle 47 * ``` 48 */ 49 inline operator fun Rect.component2() = this.top 50 51 /** 52 * Returns "right", the third component of the rectangle. 53 * 54 * This method allows to use destructuring declarations when working with rectangles, 55 * for example: 56 * ``` 57 * val (left, top, right, bottom) = myRectangle 58 * ``` 59 */ 60 inline operator fun Rect.component3() = this.right 61 62 /** 63 * Returns "bottom", the fourth component of the rectangle. 64 * 65 * This method allows to use destructuring declarations when working with rectangles, 66 * for example: 67 * ``` 68 * val (left, top, right, bottom) = myRectangle 69 * ``` 70 */ 71 inline operator fun Rect.component4() = this.bottom 72 73 /** 74 * Returns "left", the first component of the rectangle. 75 * 76 * This method allows to use destructuring declarations when working with rectangles, 77 * for example: 78 * ``` 79 * val (left, top, right, bottom) = myRectangle 80 * ``` 81 */ 82 inline operator fun RectF.component1() = this.left 83 84 /** 85 * Returns "top", the second component of the rectangle. 86 * 87 * This method allows to use destructuring declarations when working with rectangles, 88 * for example: 89 * ``` 90 * val (left, top, right, bottom) = myRectangle 91 * ``` 92 */ 93 inline operator fun RectF.component2() = this.top 94 95 /** 96 * Returns "right", the third component of the rectangle. 97 * 98 * This method allows to use destructuring declarations when working with rectangles, 99 * for example: 100 * ``` 101 * val (left, top, right, bottom) = myRectangle 102 * ``` 103 */ 104 inline operator fun RectF.component3() = this.right 105 106 /** 107 * Returns "bottom", the fourth component of the rectangle. 108 * 109 * This method allows to use destructuring declarations when working with rectangles, 110 * for example: 111 * ``` 112 * val (left, top, right, bottom) = myRectangle 113 * ``` 114 */ 115 inline operator fun RectF.component4() = this.bottom 116 117 /** 118 * Performs the union of this rectangle and the specified rectangle and returns 119 * the result as a new rectangle. 120 */ 121 inline operator fun Rect.plus(r: Rect): Rect { 122 return Rect(this).apply { 123 union(r) 124 } 125 } 126 127 /** 128 * Performs the union of this rectangle and the specified rectangle and returns 129 * the result as a new rectangle. 130 */ 131 inline operator fun RectF.plus(r: RectF): RectF { 132 return RectF(this).apply { 133 union(r) 134 } 135 } 136 137 /** 138 * Returns a new rectangle representing this rectangle offset by the specified 139 * amount on both X and Y axis. 140 */ 141 inline operator fun Rect.plus(xy: Int): Rect { 142 return Rect(this).apply { 143 offset(xy, xy) 144 } 145 } 146 147 /** 148 * Returns a new rectangle representing this rectangle offset by the specified 149 * amount on both X and Y axis. 150 */ 151 inline operator fun RectF.plus(xy: Float): RectF { 152 return RectF(this).apply { 153 offset(xy, xy) 154 } 155 } 156 157 /** 158 * Returns a new rectangle representing this rectangle offset by the specified 159 * point. 160 */ 161 inline operator fun Rect.plus(xy: Point): Rect { 162 return Rect(this).apply { 163 offset(xy.x, xy.y) 164 } 165 } 166 167 /** 168 * Returns a new rectangle representing this rectangle offset by the specified 169 * point. 170 */ 171 inline operator fun RectF.plus(xy: PointF): RectF { 172 return RectF(this).apply { 173 offset(xy.x, xy.y) 174 } 175 } 176 177 /** 178 * Returns the difference of this rectangle and the specified rectangle as a new region. 179 */ 180 inline operator fun Rect.minus(r: Rect): Region { 181 return Region(this).apply { 182 op(r, Region.Op.DIFFERENCE) 183 } 184 } 185 186 /** 187 * Returns the difference of this rectangle and the specified rectangle as a new region. 188 * This rectangle is first converted to a [Rect] using [RectF.toRect]. 189 */ 190 inline operator fun RectF.minus(r: RectF): Region { 191 return Region(this.toRect()).apply { 192 op(r.toRect(), Region.Op.DIFFERENCE) 193 } 194 } 195 196 /** 197 * Returns a new rectangle representing this rectangle offset by the negation 198 * of the specified amount on both X and Y axis. 199 */ 200 inline operator fun Rect.minus(xy: Int): Rect { 201 return Rect(this).apply { 202 offset(-xy, -xy) 203 } 204 } 205 206 /** 207 * Returns a new rectangle representing this rectangle offset by the negation 208 * of the specified amount on both X and Y axis. 209 */ 210 inline operator fun RectF.minus(xy: Float): RectF { 211 return RectF(this).apply { 212 offset(-xy, -xy) 213 } 214 } 215 216 /** 217 * Returns a new rectangle representing this rectangle offset by the negation of 218 * the specified point. 219 */ 220 inline operator fun Rect.minus(xy: Point): Rect { 221 return Rect(this).apply { 222 offset(-xy.x, -xy.y) 223 } 224 } 225 226 /** 227 * Returns a new rectangle representing this rectangle offset by the negation of 228 * the specified point. 229 */ 230 inline operator fun RectF.minus(xy: PointF): RectF { 231 return RectF(this).apply { 232 offset(-xy.x, -xy.y) 233 } 234 } 235 236 /** 237 * Returns the union of two rectangles as a new rectangle. 238 */ 239 inline infix fun Rect.and(r: Rect) = this + r 240 241 /** 242 * Returns the union of two rectangles as a new rectangle. 243 */ 244 inline infix fun RectF.and(r: RectF) = this + r 245 246 /** 247 * Returns the intersection of two rectangles as a new rectangle. 248 * If the rectangles do not intersect, returns a copy of the left hand side 249 * rectangle. 250 */ 251 @SuppressLint("CheckResult") 252 inline infix fun Rect.or(r: Rect): Rect { 253 return Rect(this).apply { 254 intersect(r) 255 } 256 } 257 258 /** 259 * Returns the intersection of two rectangles as a new rectangle. 260 * If the rectangles do not intersect, returns a copy of the left hand side 261 * rectangle. 262 */ 263 @SuppressLint("CheckResult") 264 inline infix fun RectF.or(r: RectF): RectF { 265 return RectF(this).apply { 266 intersect(r) 267 } 268 } 269 270 /** 271 * Returns the union minus the intersection of two rectangles as a new region. 272 */ 273 inline infix fun Rect.xor(r: Rect): Region { 274 return Region(this).apply { 275 op(r, Region.Op.XOR) 276 } 277 } 278 279 /** 280 * Returns the union minus the intersection of two rectangles as a new region. 281 * The two rectangles are first converted to [Rect] using [RectF.toRect]. 282 */ 283 inline infix fun RectF.xor(r: RectF): Region { 284 return Region(this.toRect()).apply { 285 op(r.toRect(), Region.Op.XOR) 286 } 287 } 288 289 /** 290 * Returns true if the specified point is inside the rectangle. 291 * The left and top are considered to be inside, while the right and bottom are not. 292 * This means that for a point to be contained: left <= x < right and top <= y < bottom. 293 * An empty rectangle never contains any point. 294 */ 295 inline operator fun Rect.contains(p: Point) = contains(p.x, p.y) 296 297 /** 298 * Returns true if the specified point is inside the rectangle. 299 * The left and top are considered to be inside, while the right and bottom are not. 300 * This means that for a point to be contained: left <= x < right and top <= y < bottom. 301 * An empty rectangle never contains any point. 302 */ 303 inline operator fun RectF.contains(p: PointF) = contains(p.x, p.y) 304 305 /** 306 * Returns a [RectF] representation of this rectangle. 307 */ 308 inline fun Rect.toRectF(): RectF = RectF(this) 309 310 /** 311 * Returns a [Rect] representation of this rectangle. The resulting rect will be sized such 312 * that this rect can fit within it. 313 */ 314 inline fun RectF.toRect(): Rect { 315 val r = Rect() 316 roundOut(r) 317 return r 318 } 319 320 /** 321 * Returns a [Region] representation of this rectangle. 322 */ 323 inline fun Rect.toRegion() = Region(this) 324 325 /** 326 * Returns a [Region] representation of this rectangle. The resulting rect will be sized such 327 * that this rect can fit within it. 328 */ 329 inline fun RectF.toRegion() = Region(this.toRect()) 330 331 /** 332 * Transform this rectangle in place using the supplied [Matrix] and returns 333 * this rectangle. 334 */ 335 inline fun RectF.transform(m: Matrix) = apply { m.mapRect(this@transform) } 336