| 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2004, 2007 IBM Corporation and others. |
| 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the Eclipse Public License v1.0 |
| 5 | * which accompanies this distribution, and is available at |
| 6 | * http://www.eclipse.org/legal/epl-v10.html |
| 7 | * |
| 8 | * Contributors: |
| 9 | * IBM Corporation - initial API and implementation |
| 10 | *******************************************************************************/ |
| 11 | package org.eclipse.jface.util; |
| 12 | |
| 13 | import org.eclipse.swt.SWT; |
| 14 | import org.eclipse.swt.graphics.Point; |
| 15 | import org.eclipse.swt.graphics.Rectangle; |
| 16 | import org.eclipse.swt.widgets.Control; |
| 17 | |
| 18 | /** |
| 19 | * Contains static methods for performing simple geometric operations |
| 20 | * on the SWT geometry classes. |
| 21 | * |
| 22 | * @since 3.0 |
| 23 | */ |
| 24 | public class Geometry { |
| 25 | |
| 26 | /** |
| 27 | * Prevent this class from being instantiated. |
| 28 | * |
| 29 | * @since 3.0 |
| 30 | */ |
| 31 | private Geometry() { |
| 32 | //This is not instantiated |
| 33 | } |
| 34 | |
| 35 | /** |
| 36 | * Returns the square of the distance between two points. |
| 37 | * <p>This is preferred over the real distance when searching |
| 38 | * for the closest point, since it avoids square roots.</p> |
| 39 | * |
| 40 | * @param p1 first endpoint |
| 41 | * @param p2 second endpoint |
| 42 | * @return the square of the distance between the two points |
| 43 | * |
| 44 | * @since 3.0 |
| 45 | */ |
| 46 | public static int distanceSquared(Point p1, Point p2) { |
| 47 | int term1 = p1.x - p2.x; |
| 48 | int term2 = p1.y - p2.y; |
| 49 | return term1 * term1 + term2 * term2; |
| 50 | } |
| 51 | |
| 52 | /** |
| 53 | * Returns the magnitude of the given 2d vector (represented as a Point) |
| 54 | * |
| 55 | * @param p point representing the 2d vector whose magnitude is being computed |
| 56 | * @return the magnitude of the given 2d vector |
| 57 | * @since 3.0 |
| 58 | */ |
| 59 | public static double magnitude(Point p) { |
| 60 | return Math.sqrt(magnitudeSquared(p)); |
| 61 | } |
| 62 | |
| 63 | /** |
| 64 | * Returns the square of the magnitude of the given 2-space vector (represented |
| 65 | * using a point) |
| 66 | * |
| 67 | * @param p the point whose magnitude is being computed |
| 68 | * @return the square of the magnitude of the given vector |
| 69 | * @since 3.0 |
| 70 | */ |
| 71 | public static int magnitudeSquared(Point p) { |
| 72 | return p.x * p.x + p.y * p.y; |
| 73 | } |
| 74 | |
| 75 | /** |
| 76 | * Returns the dot product of the given vectors (expressed as Points) |
| 77 | * |
| 78 | * @param p1 the first vector |
| 79 | * @param p2 the second vector |
| 80 | * @return the dot product of the two vectors |
| 81 | * @since 3.0 |
| 82 | */ |
| 83 | public static int dotProduct(Point p1, Point p2) { |
| 84 | return p1.x * p2.x + p1.y * p2.y; |
| 85 | } |
| 86 | |
| 87 | /** |
| 88 | * Returns a new point whose coordinates are the minimum of the coordinates of the |
| 89 | * given points |
| 90 | * |
| 91 | * @param p1 a Point |
| 92 | * @param p2 a Point |
| 93 | * @return a new point whose coordinates are the minimum of the coordinates of the |
| 94 | * given points |
| 95 | * @since 3.0 |
| 96 | */ |
| 97 | public static Point min(Point p1, Point p2) { |
| 98 | return new Point(Math.min(p1.x, p2.x), Math.min(p1.y, p2.y)); |
| 99 | } |
| 100 | |
| 101 | /** |
| 102 | * Returns a new point whose coordinates are the maximum of the coordinates |
| 103 | * of the given points |
| 104 | * @param p1 a Point |
| 105 | * @param p2 a Point |
| 106 | * @return point a new point whose coordinates are the maximum of the coordinates |
| 107 | * @since 3.0 |
| 108 | */ |
| 109 | public static Point max(Point p1, Point p2) { |
| 110 | return new Point(Math.max(p1.x, p2.x), Math.max(p1.y, p2.y)); |
| 111 | } |
| 112 | |
| 113 | /** |
| 114 | * Returns a vector in the given direction with the given |
| 115 | * magnitude. Directions are given using SWT direction constants, and |
| 116 | * the resulting vector is in the screen's coordinate system. That is, |
| 117 | * the vector (0, 1) is down and the vector (1, 0) is right. |
| 118 | * |
| 119 | * @param distance magnitude of the vector |
| 120 | * @param direction one of SWT.TOP, SWT.BOTTOM, SWT.LEFT, or SWT.RIGHT |
| 121 | * @return a point representing a vector in the given direction with the given magnitude |
| 122 | * @since 3.0 |
| 123 | */ |
| 124 | public static Point getDirectionVector(int distance, int direction) { |
| 125 | switch (direction) { |
| 126 | case SWT.TOP: |
| 127 | return new Point(0, -distance); |
| 128 | case SWT.BOTTOM: |
| 129 | return new Point(0, distance); |
| 130 | case SWT.LEFT: |
| 131 | return new Point(-distance, 0); |
| 132 | case SWT.RIGHT: |
| 133 | return new Point(distance, 0); |
| 134 | } |
| 135 | |
| 136 | return new Point(0, 0); |
| 137 | } |
| 138 | |
| 139 | /** |
| 140 | * Returns the point in the center of the given rectangle. |
| 141 | * |
| 142 | * @param rect rectangle being computed |
| 143 | * @return a Point at the center of the given rectangle. |
| 144 | * @since 3.0 |
| 145 | */ |
| 146 | public static Point centerPoint(Rectangle rect) { |
| 147 | return new Point(rect.x + rect.width / 2, rect.y + rect.height / 2); |
| 148 | } |
| 149 | |
| 150 | /** |
| 151 | * Returns a copy of the given point |
| 152 | * |
| 153 | * @param toCopy point to copy |
| 154 | * @return a copy of the given point |
| 155 | */ |
| 156 | public static Point copy(Point toCopy) { |
| 157 | return new Point(toCopy.x, toCopy.y); |
| 158 | } |
| 159 | |
| 160 | /** |
| 161 | * Sets result equal to toCopy |
| 162 | * |
| 163 | * @param result object that will be modified |
| 164 | * @param toCopy object that will be copied |
| 165 | * @since 3.1 |
| 166 | */ |
| 167 | public static void set(Point result, Point toCopy) { |
| 168 | result.x = toCopy.x; |
| 169 | result.y = toCopy.y; |
| 170 | } |
| 171 | |
| 172 | /** |
| 173 | * Sets result equal to toCopy |
| 174 | * |
| 175 | * @param result object that will be modified |
| 176 | * @param toCopy object that will be copied |
| 177 | * @since 3.1 |
| 178 | */ |
| 179 | public static void set(Rectangle result, Rectangle toCopy) { |
| 180 | result.x = toCopy.x; |
| 181 | result.y = toCopy.y; |
| 182 | result.width = toCopy.width; |
| 183 | result.height = toCopy.height; |
| 184 | } |
| 185 | |
| 186 | /** |
| 187 | * <p>Returns a new difference Rectangle whose x, y, width, and height are equal to the difference of the corresponding |
| 188 | * attributes from the given rectangles</p> |
| 189 | * |
| 190 | * <p></p> |
| 191 | * <b>Example: Compute the margins for a given Composite, and apply those same margins to a new GridLayout</b> |
| 192 | * |
| 193 | * <code><pre> |
| 194 | * // Compute the client area, in the coordinate system of the input composite's parent |
| 195 | * Rectangle clientArea = Display.getCurrent().map(inputComposite, |
| 196 | * inputComposite.getParent(), inputComposite.getClientArea()); |
| 197 | * |
| 198 | * // Compute the margins for a given Composite by subtracting the client area from the composite's bounds |
| 199 | * Rectangle margins = Geometry.subtract(inputComposite.getBounds(), clientArea); |
| 200 | * |
| 201 | * // Now apply these margins to a new GridLayout |
| 202 | * GridLayout layout = GridLayoutFactory.fillDefaults().margins(margins).create(); |
| 203 | * </pre></code> |
| 204 | * |
| 205 | * @param rect1 first rectangle |
| 206 | * @param rect2 rectangle to subtract |
| 207 | * @return the difference between the two rectangles (computed as rect1 - rect2) |
| 208 | * @since 3.3 |
| 209 | */ |
| 210 | public static Rectangle subtract(Rectangle rect1, Rectangle rect2) { |
| 211 | return new Rectangle(rect1.x - rect2.x, rect1.y - rect2.y, rect1.width - rect2.width, rect1.height - rect2.height); |
| 212 | } |
| 213 | |
| 214 | /** |
| 215 | * <p>Returns a new Rectangle whose x, y, width, and height is the sum of the x, y, width, and height values of |
| 216 | * both rectangles respectively.</p> |
| 217 | * |
| 218 | * @param rect1 first rectangle to add |
| 219 | * @param rect2 second rectangle to add |
| 220 | * @return a new rectangle whose x, y, height, and width attributes are the sum of the corresponding attributes from |
| 221 | * the arguments. |
| 222 | * @since 3.3 |
| 223 | */ |
| 224 | public static Rectangle add(Rectangle rect1, Rectangle rect2) { |
| 225 | return new Rectangle(rect1.x + rect2.x, rect1.y + rect2.y, |
| 226 | rect1.width + rect2.width, rect1.height + rect2.height); |
| 227 | } |
| 228 | |
| 229 | /** |
| 230 | * Adds two points as 2d vectors. Returns a new point whose coordinates are |
| 231 | * the sum of the original two points. |
| 232 | * |
| 233 | * @param point1 the first point (not null) |
| 234 | * @param point2 the second point (not null) |
| 235 | * @return a new point whose coordinates are the sum of the given points |
| 236 | * @since 3.0 |
| 237 | */ |
| 238 | public static Point add(Point point1, Point point2) { |
| 239 | return new Point(point1.x + point2.x, point1.y + point2.y); |
| 240 | } |
| 241 | |
| 242 | /** |
| 243 | * Divides both coordinates of the given point by the given scalar. |
| 244 | * |
| 245 | * @since 3.1 |
| 246 | * |
| 247 | * @param toDivide point to divide |
| 248 | * @param scalar denominator |
| 249 | * @return a new Point whose coordinates are equal to the original point divided by the scalar |
| 250 | */ |
| 251 | public static Point divide(Point toDivide, int scalar) { |
| 252 | return new Point(toDivide.x / scalar, toDivide.y / scalar); |
| 253 | } |
| 254 | |
| 255 | |
| 256 | /** |
| 257 | * Performs vector subtraction on two points. Returns a new point equal to |
| 258 | * (point1 - point2). |
| 259 | * |
| 260 | * @param point1 initial point |
| 261 | * @param point2 vector to subtract |
| 262 | * @return the difference (point1 - point2) |
| 263 | * @since 3.0 |
| 264 | */ |
| 265 | public static Point subtract(Point point1, Point point2) { |
| 266 | return new Point(point1.x - point2.x, point1.y - point2.y); |
| 267 | } |
| 268 | |
| 269 | /** |
| 270 | * Swaps the X and Y coordinates of the given point. |
| 271 | * |
| 272 | * @param toFlip modifies this point |
| 273 | * @since 3.1 |
| 274 | */ |
| 275 | public static void flipXY(Point toFlip) { |
| 276 | int temp = toFlip.x; |
| 277 | toFlip.x = toFlip.y; |
| 278 | toFlip.y = temp; |
| 279 | } |
| 280 | |
| 281 | /** |
| 282 | * Swaps the X and Y coordinates of the given rectangle, along with the height and width. |
| 283 | * |
| 284 | * @param toFlip modifies this rectangle |
| 285 | * @since 3.1 |
| 286 | */ |
| 287 | public static void flipXY(Rectangle toFlip) { |
| 288 | int temp = toFlip.x; |
| 289 | toFlip.x = toFlip.y; |
| 290 | toFlip.y = temp; |
| 291 | |
| 292 | temp = toFlip.width; |
| 293 | toFlip.width = toFlip.height; |
| 294 | toFlip.height = temp; |
| 295 | } |
| 296 | |
| 297 | /** |
| 298 | * Returns the height or width of the given rectangle. |
| 299 | * |
| 300 | * @param toMeasure rectangle to measure |
| 301 | * @param width returns the width if true, and the height if false |
| 302 | * @return the width or height of the given rectangle |
| 303 | * @since 3.0 |
| 304 | */ |
| 305 | public static int getDimension(Rectangle toMeasure, boolean width) { |
| 306 | if (width) { |
| 307 | return toMeasure.width; |
| 308 | } |
| 309 | return toMeasure.height; |
| 310 | } |
| 311 | |
| 312 | /** |
| 313 | * Returns the x or y coordinates of the given point. |
| 314 | * |
| 315 | * @param toMeasure point being measured |
| 316 | * @param width if true, returns x. Otherwise, returns y. |
| 317 | * @return the x or y coordinate |
| 318 | * @since 3.1 |
| 319 | */ |
| 320 | public static int getCoordinate(Point toMeasure, boolean width) { |
| 321 | return width ? toMeasure.x : toMeasure.y; |
| 322 | } |
| 323 | |
| 324 | /** |
| 325 | * Returns the x or y coordinates of the given rectangle. |
| 326 | * |
| 327 | * @param toMeasure rectangle being measured |
| 328 | * @param width if true, returns x. Otherwise, returns y. |
| 329 | * @return the x or y coordinate |
| 330 | * @since 3.1 |
| 331 | */ |
| 332 | public static int getCoordinate(Rectangle toMeasure, boolean width) { |
| 333 | return width ? toMeasure.x : toMeasure.y; |
| 334 | } |
| 335 | |
| 336 | /** |
| 337 | * Sets one dimension of the given rectangle. Modifies the given rectangle. |
| 338 | * |
| 339 | * @param toSet rectangle to modify |
| 340 | * @param width if true, the width is modified. If false, the height is modified. |
| 341 | * @param newCoordinate new value of the width or height |
| 342 | * @since 3.1 |
| 343 | */ |
| 344 | public static void setDimension(Rectangle toSet, boolean width, int newCoordinate) { |
| 345 | if (width) { |
| 346 | toSet.width = newCoordinate; |
| 347 | } else { |
| 348 | toSet.height = newCoordinate; |
| 349 | } |
| 350 | } |
| 351 | |
| 352 | /** |
| 353 | * Sets one coordinate of the given rectangle. Modifies the given rectangle. |
| 354 | * |
| 355 | * @param toSet rectangle to modify |
| 356 | * @param width if true, the x coordinate is modified. If false, the y coordinate is modified. |
| 357 | * @param newCoordinate new value of the x or y coordinates |
| 358 | * @since 3.1 |
| 359 | */ |
| 360 | public static void setCoordinate(Rectangle toSet, boolean width, int newCoordinate) { |
| 361 | if (width) { |
| 362 | toSet.x = newCoordinate; |
| 363 | } else { |
| 364 | toSet.y = newCoordinate; |
| 365 | } |
| 366 | } |
| 367 | |
| 368 | /** |
| 369 | * Sets one coordinate of the given point. Modifies the given point. |
| 370 | * |
| 371 | * @param toSet point to modify |
| 372 | * @param width if true, the x coordinate is modified. If false, the y coordinate is modified. |
| 373 | * @param newCoordinate new value of the x or y coordinates |
| 374 | * @since 3.1 |
| 375 | */ |
| 376 | public static void setCoordinate(Point toSet, boolean width, int newCoordinate) { |
| 377 | if (width) { |
| 378 | toSet.x = newCoordinate; |
| 379 | } else { |
| 380 | toSet.y = newCoordinate; |
| 381 | } |
| 382 | } |
| 383 | |
| 384 | /** |
| 385 | * Returns the distance of the given point from a particular side of the given rectangle. |
| 386 | * Returns negative values for points outside the rectangle. |
| 387 | * |
| 388 | * @param rectangle a bounding rectangle |
| 389 | * @param testPoint a point to test |
| 390 | * @param edgeOfInterest side of the rectangle to test against |
| 391 | * @return the distance of the given point from the given edge of the rectangle |
| 392 | * @since 3.0 |
| 393 | */ |
| 394 | public static int getDistanceFromEdge(Rectangle rectangle, Point testPoint, |
| 395 | int edgeOfInterest) { |
| 396 | switch (edgeOfInterest) { |
| 397 | case SWT.TOP: |
| 398 | return testPoint.y - rectangle.y; |
| 399 | case SWT.BOTTOM: |
| 400 | return rectangle.y + rectangle.height - testPoint.y; |
| 401 | case SWT.LEFT: |
| 402 | return testPoint.x - rectangle.x; |
| 403 | case SWT.RIGHT: |
| 404 | return rectangle.x + rectangle.width - testPoint.x; |
| 405 | } |
| 406 | |
| 407 | return 0; |
| 408 | } |
| 409 | |
| 410 | /** |
| 411 | * Extrudes the given edge inward by the given distance. That is, if one side of the rectangle |
| 412 | * was sliced off with a given thickness, this returns the rectangle that forms the slice. Note |
| 413 | * that the returned rectangle will be inside the given rectangle if size > 0. |
| 414 | * |
| 415 | * @param toExtrude the rectangle to extrude. The resulting rectangle will share three sides |
| 416 | * with this rectangle. |
| 417 | * @param size distance to extrude. A negative size will extrude outwards (that is, the resulting |
| 418 | * rectangle will overlap the original iff this is positive). |
| 419 | * @param orientation the side to extrude. One of SWT.LEFT, SWT.RIGHT, SWT.TOP, or SWT.BOTTOM. The |
| 420 | * resulting rectangle will always share this side with the original rectangle. |
| 421 | * @return a rectangle formed by extruding the given side of the rectangle by the given distance. |
| 422 | * @since 3.0 |
| 423 | */ |
| 424 | public static Rectangle getExtrudedEdge(Rectangle toExtrude, int size, |
| 425 | int orientation) { |
| 426 | Rectangle bounds = new Rectangle(toExtrude.x, toExtrude.y, |
| 427 | toExtrude.width, toExtrude.height); |
| 428 | |
| 429 | if (!isHorizontal(orientation)) { |
| 430 | bounds.width = size; |
| 431 | } else { |
| 432 | bounds.height = size; |
| 433 | } |
| 434 | |
| 435 | switch (orientation) { |
| 436 | case SWT.RIGHT: |
| 437 | bounds.x = toExtrude.x + toExtrude.width - bounds.width; |
| 438 | break; |
| 439 | case SWT.BOTTOM: |
| 440 | bounds.y = toExtrude.y + toExtrude.height - bounds.height; |
| 441 | break; |
| 442 | } |
| 443 | |
| 444 | normalize(bounds); |
| 445 | |
| 446 | return bounds; |
| 447 | } |
| 448 | |
| 449 | /** |
| 450 | * Returns the opposite of the given direction. That is, returns SWT.LEFT if |
| 451 | * given SWT.RIGHT and visa-versa. |
| 452 | * |
| 453 | * @param swtDirectionConstant one of SWT.LEFT, SWT.RIGHT, SWT.TOP, or SWT.BOTTOM |
| 454 | * @return one of SWT.LEFT, SWT.RIGHT, SWT.TOP, or SWT.BOTTOM |
| 455 | * @since 3.0 |
| 456 | */ |
| 457 | public static int getOppositeSide(int swtDirectionConstant) { |
| 458 | switch (swtDirectionConstant) { |
| 459 | case SWT.TOP: |
| 460 | return SWT.BOTTOM; |
| 461 | case SWT.BOTTOM: |
| 462 | return SWT.TOP; |
| 463 | case SWT.LEFT: |
| 464 | return SWT.RIGHT; |
| 465 | case SWT.RIGHT: |
| 466 | return SWT.LEFT; |
| 467 | } |
| 468 | |
| 469 | return swtDirectionConstant; |
| 470 | } |
| 471 | |
| 472 | /** |
| 473 | * Converts the given boolean into an SWT orientation constant. |
| 474 | * |
| 475 | * @param horizontal if true, returns SWT.HORIZONTAL. If false, returns SWT.VERTICAL |
| 476 | * @return SWT.HORIZONTAL or SWT.VERTICAL. |
| 477 | * @since 3.0 |
| 478 | */ |
| 479 | public static int getSwtHorizontalOrVerticalConstant(boolean horizontal) { |
| 480 | if (horizontal) { |
| 481 | return SWT.HORIZONTAL; |
| 482 | } |
| 483 | return SWT.VERTICAL; |
| 484 | } |
| 485 | |
| 486 | /** |
| 487 | * Returns true iff the given SWT side constant corresponds to a horizontal side |
| 488 | * of a rectangle. That is, returns true for the top and bottom but false for the |
| 489 | * left and right. |
| 490 | * |
| 491 | * @param swtSideConstant one of SWT.TOP, SWT.BOTTOM, SWT.LEFT, or SWT.RIGHT |
| 492 | * @return true iff the given side is horizontal. |
| 493 | * @since 3.0 |
| 494 | */ |
| 495 | public static boolean isHorizontal(int swtSideConstant) { |
| 496 | return !(swtSideConstant == SWT.LEFT || swtSideConstant == SWT.RIGHT); |
| 497 | } |
| 498 | |
| 499 | /** |
| 500 | * Moves the given rectangle by the given delta. |
| 501 | * |
| 502 | * @param rect rectangle to move (will be modified) |
| 503 | * @param delta direction vector to move the rectangle by |
| 504 | * @since 3.0 |
| 505 | */ |
| 506 | public static void moveRectangle(Rectangle rect, Point delta) { |
| 507 | rect.x += delta.x; |
| 508 | rect.y += delta.y; |
| 509 | } |
| 510 | |
| 511 | /** |
| 512 | * Moves each edge of the given rectangle outward by the given amount. Negative values |
| 513 | * cause the rectangle to contract. Does not allow the rectangle's width or height to be |
| 514 | * reduced below zero. |
| 515 | * |
| 516 | * @param rect normalized rectangle to modify |
| 517 | * @param differenceRect difference rectangle to be added to rect |
| 518 | * @since 3.3 |
| 519 | */ |
| 520 | public static void expand(Rectangle rect, Rectangle differenceRect) { |
| 521 | rect.x += differenceRect.x; |
| 522 | rect.y += differenceRect.y; |
| 523 | rect.height = Math.max(0, rect.height + differenceRect.height); |
| 524 | rect.width = Math.max(0, rect.width + differenceRect.width); |
| 525 | } |
| 526 | |
| 527 | /** |
| 528 | * <p>Returns a rectangle which, when added to another rectangle, will expand each side |
| 529 | * by the given number of units.</p> |
| 530 | * |
| 531 | * <p>This is commonly used to store margin sizes. For example:</p> |
| 532 | * |
| 533 | * <code><pre> |
| 534 | * // Expands the left, right, top, and bottom |
| 535 | * // of the given control by 10, 5, 1, and 15 units respectively |
| 536 | * |
| 537 | * Rectangle margins = Geometry.createDifferenceRect(10,5,1,15); |
| 538 | * Rectangle bounds = someControl.getBounds(); |
| 539 | * someControl.setBounds(Geometry.add(bounds, margins)); |
| 540 | * </pre></code> |
| 541 | * |
| 542 | * @param left distance to expand the left side (negative values move the edge inward) |
| 543 | * @param right distance to expand the right side (negative values move the edge inward) |
| 544 | * @param top distance to expand the top (negative values move the edge inward) |
| 545 | * @param bottom distance to expand the bottom (negative values move the edge inward) |
| 546 | * |
| 547 | * @return a difference rectangle that, when added to another rectangle, will cause each |
| 548 | * side to expand by the given number of units |
| 549 | * @since 3.3 |
| 550 | */ |
| 551 | public static Rectangle createDiffRectangle(int left, int right, int top, int bottom) { |
| 552 | return new Rectangle(-left, -top, left + right, top + bottom); |
| 553 | } |
| 554 | |
| 555 | /** |
| 556 | * Moves each edge of the given rectangle outward by the given amount. Negative values |
| 557 | * cause the rectangle to contract. Does not allow the rectangle's width or height to be |
| 558 | * reduced below zero. |
| 559 | * |
| 560 | * @param rect normalized rectangle to modify |
| 561 | * @param left distance to move the left edge outward (negative values move the edge inward) |
| 562 | * @param right distance to move the right edge outward (negative values move the edge inward) |
| 563 | * @param top distance to move the top edge outward (negative values move the edge inward) |
| 564 | * @param bottom distance to move the bottom edge outward (negative values move the edge inward) |
| 565 | * @since 3.1 |
| 566 | */ |
| 567 | public static void expand(Rectangle rect, int left, int right, int top, int bottom) { |
| 568 | rect.x -= left; |
| 569 | rect.width = Math.max(0, rect.width + left + right); |
| 570 | rect.y -= top; |
| 571 | rect.height = Math.max(0, rect.height + top + bottom); |
| 572 | } |
| 573 | |
| 574 | /** |
| 575 | * Normalizes the given rectangle. That is, any rectangle with |
| 576 | * negative width or height becomes a rectangle with positive |
| 577 | * width or height that extends to the upper-left of the original |
| 578 | * rectangle. |
| 579 | * |
| 580 | * @param rect rectangle to modify |
| 581 | * @since 3.0 |
| 582 | */ |
| 583 | public static void normalize(Rectangle rect) { |
| 584 | if (rect.width < 0) { |
| 585 | rect.width = -rect.width; |
| 586 | rect.x -= rect.width; |
| 587 | } |
| 588 | |
| 589 | if (rect.height < 0) { |
| 590 | rect.height = -rect.height; |
| 591 | rect.y -= rect.height; |
| 592 | } |
| 593 | } |
| 594 | |
| 595 | /** |
| 596 | * Converts the given rectangle from display coordinates to the local coordinate system |
| 597 | * of the given object into display coordinates. |
| 598 | * |
| 599 | * @param coordinateSystem local coordinate system being converted to |
| 600 | * @param toConvert rectangle to convert |
| 601 | * @return a rectangle in control coordinates |
| 602 | * @since 3.0 |
| 603 | */ |
| 604 | public static Rectangle toControl(Control coordinateSystem, |
| 605 | Rectangle toConvert) { |
| 606 | return(coordinateSystem.getDisplay().map |
| 607 | (null,coordinateSystem,toConvert)); |
| 608 | } |
| 609 | |
| 610 | /** |
| 611 | * Converts the given rectangle from the local coordinate system of the given object |
| 612 | * into display coordinates. |
| 613 | * |
| 614 | * @param coordinateSystem local coordinate system being converted from |
| 615 | * @param toConvert rectangle to convert |
| 616 | * @return a rectangle in display coordinates |
| 617 | * @since 3.0 |
| 618 | */ |
| 619 | public static Rectangle toDisplay(Control coordinateSystem, |
| 620 | Rectangle toConvert) { |
| 621 | return(coordinateSystem.getDisplay().map |
| 622 | (coordinateSystem,null,toConvert)); |
| 623 | |
| 624 | } |
| 625 | |
| 626 | /** |
| 627 | * Determines where the given point lies with respect to the given rectangle. |
| 628 | * Returns a combination of SWT.LEFT, SWT.RIGHT, SWT.TOP, and SWT.BOTTOM, combined |
| 629 | * with bitwise or (for example, returns SWT.TOP | SWT.LEFT if the point is to the |
| 630 | * upper-left of the rectangle). Returns 0 if the point lies within the rectangle. |
| 631 | * Positions are in screen coordinates (ie: a point is to the upper-left of the |
| 632 | * rectangle if its x and y coordinates are smaller than any point in the rectangle) |
| 633 | * |
| 634 | * @param boundary normalized boundary rectangle |
| 635 | * @param toTest point whose relative position to the rectangle is being computed |
| 636 | * @return one of SWT.LEFT | SWT.TOP, SWT.TOP, SWT.RIGHT | SWT.TOP, SWT.LEFT, 0, |
| 637 | * SWT.RIGHT, SWT.LEFT | SWT.BOTTOM, SWT.BOTTOM, SWT.RIGHT | SWT.BOTTOM |
| 638 | * @since 3.0 |
| 639 | */ |
| 640 | public static int getRelativePosition(Rectangle boundary, Point toTest) { |
| 641 | int result = 0; |
| 642 | |
| 643 | if (toTest.x < boundary.x) { |
| 644 | result |= SWT.LEFT; |
| 645 | } else if (toTest.x >= boundary.x + boundary.width) { |
| 646 | result |= SWT.RIGHT; |
| 647 | } |
| 648 | |
| 649 | if (toTest.y < boundary.y) { |
| 650 | result |= SWT.TOP; |
| 651 | } else if (toTest.y >= boundary.y + boundary.height) { |
| 652 | result |= SWT.BOTTOM; |
| 653 | } |
| 654 | |
| 655 | return result; |
| 656 | } |
| 657 | |
| 658 | /** |
| 659 | * Returns the distance from the point to the nearest edge of the given |
| 660 | * rectangle. Returns negative values if the point lies outside the rectangle. |
| 661 | * |
| 662 | * @param boundary rectangle to test |
| 663 | * @param toTest point to test |
| 664 | * @return the distance between the given point and the nearest edge of the rectangle. |
| 665 | * Returns positive values for points inside the rectangle and negative values for points |
| 666 | * outside the rectangle. |
| 667 | * @since 3.1 |
| 668 | */ |
| 669 | public static int getDistanceFrom(Rectangle boundary, Point toTest) { |
| 670 | int side = getClosestSide(boundary, toTest); |
| 671 | return getDistanceFromEdge(boundary, toTest, side); |
| 672 | } |
| 673 | |
| 674 | /** |
| 675 | * Returns the edge of the given rectangle is closest to the given |
| 676 | * point. |
| 677 | * |
| 678 | * @param boundary rectangle to test |
| 679 | * @param toTest point to compare |
| 680 | * @return one of SWT.LEFT, SWT.RIGHT, SWT.TOP, or SWT.BOTTOM |
| 681 | * |
| 682 | * @since 3.0 |
| 683 | */ |
| 684 | public static int getClosestSide(Rectangle boundary, Point toTest) { |
| 685 | int[] sides = new int[] { SWT.LEFT, SWT.RIGHT, SWT.TOP, SWT.BOTTOM }; |
| 686 | |
| 687 | int closestSide = SWT.LEFT; |
| 688 | int closestDistance = Integer.MAX_VALUE; |
| 689 | |
| 690 | for (int idx = 0; idx < sides.length; idx++) { |
| 691 | int side = sides[idx]; |
| 692 | |
| 693 | int distance = getDistanceFromEdge(boundary, toTest, side); |
| 694 | |
| 695 | if (distance < closestDistance) { |
| 696 | closestDistance = distance; |
| 697 | closestSide = side; |
| 698 | } |
| 699 | } |
| 700 | |
| 701 | return closestSide; |
| 702 | } |
| 703 | |
| 704 | /** |
| 705 | * Returns a copy of the given rectangle |
| 706 | * |
| 707 | * @param toCopy rectangle to copy |
| 708 | * @return a copy of the given rectangle |
| 709 | * @since 3.0 |
| 710 | */ |
| 711 | public static Rectangle copy(Rectangle toCopy) { |
| 712 | return new Rectangle(toCopy.x, toCopy.y, toCopy.width, toCopy.height); |
| 713 | } |
| 714 | |
| 715 | /** |
| 716 | * Returns the size of the rectangle, as a Point |
| 717 | * |
| 718 | * @param rectangle rectangle whose size is being computed |
| 719 | * @return the size of the given rectangle |
| 720 | * @since 3.0 |
| 721 | */ |
| 722 | public static Point getSize(Rectangle rectangle) { |
| 723 | return new Point(rectangle.width, rectangle.height); |
| 724 | } |
| 725 | |
| 726 | /** |
| 727 | * Sets the size of the given rectangle to the given size |
| 728 | * |
| 729 | * @param rectangle rectangle to modify |
| 730 | * @param newSize new size of the rectangle |
| 731 | * @since 3.0 |
| 732 | */ |
| 733 | public static void setSize(Rectangle rectangle, Point newSize) { |
| 734 | rectangle.width = newSize.x; |
| 735 | rectangle.height = newSize.y; |
| 736 | } |
| 737 | |
| 738 | /** |
| 739 | * Sets the x,y position of the given rectangle. For a normalized |
| 740 | * rectangle (a rectangle with positive width and height), this will |
| 741 | * be the upper-left corner of the rectangle. |
| 742 | * |
| 743 | * @param rectangle rectangle to modify |
| 744 | * @param newLocation new location of the rectangle |
| 745 | * |
| 746 | * @since 3.0 |
| 747 | */ |
| 748 | public static void setLocation(Rectangle rectangle, Point newLocation) { |
| 749 | rectangle.x = newLocation.x; |
| 750 | rectangle.y = newLocation.y; |
| 751 | } |
| 752 | |
| 753 | /** |
| 754 | * Returns the x,y position of the given rectangle. For normalized rectangles |
| 755 | * (rectangles with positive width and height), this is the upper-left |
| 756 | * corner of the rectangle. |
| 757 | * |
| 758 | * @param toQuery rectangle to query |
| 759 | * @return a Point containing the x,y position of the rectangle |
| 760 | * |
| 761 | * @since 3.0 |
| 762 | */ |
| 763 | public static Point getLocation(Rectangle toQuery) { |
| 764 | return new Point(toQuery.x, toQuery.y); |
| 765 | } |
| 766 | |
| 767 | /** |
| 768 | * Returns a new rectangle with the given position and dimensions, expressed |
| 769 | * as points. |
| 770 | * |
| 771 | * @param position the (x,y) position of the rectangle |
| 772 | * @param size the size of the new rectangle, where (x,y) -> (width, height) |
| 773 | * @return a new Rectangle with the given position and size |
| 774 | * |
| 775 | * @since 3.0 |
| 776 | */ |
| 777 | public static Rectangle createRectangle(Point position, Point size) { |
| 778 | return new Rectangle(position.x, position.y, size.x, size.y); |
| 779 | } |
| 780 | |
| 781 | /** |
| 782 | * Repositions the 'inner' rectangle to lie completely within the bounds of the 'outer' |
| 783 | * rectangle if possible. One use for this is to ensure that, when setting a control's bounds, |
| 784 | * that they will always lie within its parent's client area (to avoid clipping). |
| 785 | * |
| 786 | * @param inner The 'inner' rectangle to be repositioned (should be smaller than the 'outer' rectangle) |
| 787 | * @param outer The 'outer' rectangle |
| 788 | */ |
| 789 | public static void moveInside(Rectangle inner, Rectangle outer) { |
| 790 | // adjust X |
| 791 | if (inner.x < outer.x) { |
| 792 | inner.x = outer.x; |
| 793 | } |
| 794 | if ((inner.x + inner.width) > (outer.x + outer.width)) { |
| 795 | inner.x -= (inner.x + inner.width) - (outer.x + outer.width); |
| 796 | } |
| 797 | |
| 798 | // Adjust Y |
| 799 | if (inner.y < outer.y) { |
| 800 | inner.y = outer.y; |
| 801 | } |
| 802 | if ((inner.y + inner.height) > (outer.y + outer.height)) { |
| 803 | inner.y -= (inner.y + inner.height) - (outer.y + outer.height); |
| 804 | } |
| 805 | } |
| 806 | |
| 807 | } |