1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php 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 com.android.ide.common.api; 18 19 import com.google.common.annotations.Beta; 20 import com.android.annotations.NonNull; 21 import com.android.annotations.Nullable; 22 23 24 /** 25 * Mutable rectangle bounds. 26 * <p/> 27 * To be valid, w >= 1 and h >= 1. 28 * By definition: 29 * - right side = x + w - 1. 30 * - bottom side = y + h - 1. 31 * <p> 32 * <b>NOTE: This is not a public or final API; if you rely on this be prepared 33 * to adjust your code for the next tools release.</b> 34 * </p> 35 */ 36 @Beta 37 public class Rect { 38 public int x, y, w, h; 39 40 /** Initialize an invalid rectangle. */ Rect()41 public Rect() { 42 } 43 44 /** Initialize rectangle to the given values. They can be invalid. */ Rect(int x, int y, int w, int h)45 public Rect(int x, int y, int w, int h) { 46 set(x, y, w, h); 47 } 48 49 /** Initialize rectangle to the given values. They can be invalid. */ Rect(@onNull Rect r)50 public Rect(@NonNull Rect r) { 51 set(r); 52 } 53 54 /** Initialize rectangle to the given values. They can be invalid. */ 55 @NonNull set(int x, int y, int w, int h)56 public Rect set(int x, int y, int w, int h) { 57 this.x = x; 58 this.y = y; 59 this.w = w; 60 this.h = h; 61 return this; 62 } 63 64 /** Initialize rectangle to match the given one. */ 65 @NonNull set(@onNull Rect r)66 public Rect set(@NonNull Rect r) { 67 set(r.x, r.y, r.w, r.h); 68 return this; 69 } 70 71 /** Returns a new instance of a rectangle with the same values. */ 72 @NonNull copy()73 public Rect copy() { 74 return new Rect(x, y, w, h); 75 } 76 77 /** Returns true if the rectangle has valid bounds, i.e. w>0 and h>0. */ isValid()78 public boolean isValid() { 79 return w > 0 && h > 0; 80 } 81 82 /** Returns true if the rectangle contains the x,y coordinates, borders included. */ contains(int x, int y)83 public boolean contains(int x, int y) { 84 return isValid() && 85 x >= this.x && 86 y >= this.y && 87 x < (this.x + this.w) && 88 y < (this.y + this.h); 89 } 90 91 /** Returns true if the rectangle contains the x,y coordinates, borders included. */ contains(@ullable Point p)92 public boolean contains(@Nullable Point p) { 93 return p != null && contains(p.x, p.y); 94 } 95 96 /** 97 * Moves this rectangle by setting it's x,y coordinates to the new values. 98 * @return Returns self, for chaining. 99 */ 100 @NonNull moveTo(int x, int y)101 public Rect moveTo(int x, int y) { 102 this.x = x; 103 this.y = y; 104 return this; 105 } 106 107 /** 108 * Offsets this rectangle by adding the given x,y deltas to the x,y coordinates. 109 * @return Returns self, for chaining. 110 */ 111 @NonNull offsetBy(int x, int y)112 public Rect offsetBy(int x, int y) { 113 this.x += x; 114 this.y += y; 115 return this; 116 } 117 118 @NonNull getCenter()119 public Point getCenter() { 120 return new Point(x + (w > 0 ? w / 2 : 0), 121 y + (h > 0 ? h / 2 : 0)); 122 } 123 124 @NonNull getTopLeft()125 public Point getTopLeft() { 126 return new Point(x, y); 127 } 128 129 @NonNull getBottomLeft()130 public Point getBottomLeft() { 131 return new Point(x, 132 y + (h > 0 ? h : 0)); 133 } 134 135 @NonNull getTopRight()136 public Point getTopRight() { 137 return new Point(x + (w > 0 ? w : 0), 138 y); 139 } 140 141 @NonNull getBottomRight()142 public Point getBottomRight() { 143 return new Point(x + (w > 0 ? w : 0), 144 y + (h > 0 ? h : 0)); 145 } 146 147 /** 148 * Returns the X coordinate of the right hand side of the rectangle 149 * 150 * @return the X coordinate of the right hand side of the rectangle 151 */ x2()152 public int x2() { 153 return x + w; 154 } 155 156 /** 157 * Returns the Y coordinate of the bottom of the rectangle 158 * 159 * @return the Y coordinate of the bottom of the rectangle 160 */ y2()161 public int y2() { 162 return y + h; 163 } 164 165 /** 166 * Returns the X coordinate of the center of the rectangle 167 * 168 * @return the X coordinate of the center of the rectangle 169 */ centerX()170 public int centerX() { 171 return x + w / 2; 172 } 173 174 /** 175 * Returns the Y coordinate of the center of the rectangle 176 * 177 * @return the Y coordinate of the center of the rectangle 178 */ centerY()179 public int centerY() { 180 return y + h / 2; 181 } 182 183 @Override toString()184 public String toString() { 185 return String.format("Rect [(%d,%d)-(%d,%d): %dx%d]", x, y, x + w, y + h, w, h); 186 } 187 188 @Override equals(Object obj)189 public boolean equals(Object obj) { 190 if (obj instanceof Rect) { 191 Rect rhs = (Rect) obj; 192 // validity must be equal on both sides. 193 if (isValid() != rhs.isValid()) { 194 return false; 195 } 196 // an invalid rect is equal to any other invalid rect regardless of coordinates 197 if (!isValid() && !rhs.isValid()) { 198 return true; 199 } 200 201 return this.x == rhs.x && this.y == rhs.y && this.w == rhs.w && this.h == rhs.h; 202 } 203 204 return false; 205 } 206 207 @Override hashCode()208 public int hashCode() { 209 int hc = x; 210 hc ^= ((y >> 8) & 0x0FFFFFF) | ((y & 0x00000FF) << 24); 211 hc ^= ((w >> 16) & 0x000FFFF) | ((w & 0x000FFFF) << 16); 212 hc ^= ((h >> 24) & 0x00000FF) | ((h & 0x0FFFFFF) << 8); 213 return hc; 214 } 215 216 /** 217 * Returns the center point in the rectangle 218 * 219 * @return the center point in the rectangle 220 */ 221 @NonNull center()222 public Point center() { 223 return new Point(x + w / 2, y + h / 2); 224 } 225 } 226