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 19package androidx.core.graphics 20 21import android.annotation.SuppressLint 22import android.graphics.Matrix 23import android.graphics.Point 24import android.graphics.PointF 25import android.graphics.Rect 26import android.graphics.RectF 27import 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 */ 38inline 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 */ 49inline 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 */ 60inline 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 */ 71inline 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 */ 82inline 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 */ 93inline 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 */ 104inline 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 */ 115inline 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 */ 121inline 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 */ 131inline 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 */ 141inline 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 */ 151inline 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 */ 161inline 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 */ 171inline 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 */ 180inline 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 */ 190inline 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 */ 200inline 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 */ 210inline 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 */ 220inline 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 */ 230inline 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 */ 239inline infix fun Rect.and(r: Rect) = this + r 240 241/** 242 * Returns the union of two rectangles as a new rectangle. 243 */ 244inline 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") 252inline 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") 264inline 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 */ 273inline 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 */ 283inline 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 */ 295inline 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 */ 303inline operator fun RectF.contains(p: PointF) = contains(p.x, p.y) 304 305/** 306 * Returns a [RectF] representation of this rectangle. 307 */ 308inline 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 */ 314inline 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 */ 323inline 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 */ 329inline fun RectF.toRegion() = Region(this.toRect()) 330 331/** 332 * Transform this rectangle in place using the supplied [Matrix] and returns 333 * this rectangle. 334 */ 335inline fun RectF.transform(m: Matrix) = apply { m.mapRect(this@transform) } 336