Source for org.jfree.ui.RectangleInsets

   1: /* ========================================================================
   2:  * JCommon : a free general purpose class library for the Java(tm) platform
   3:  * ========================================================================
   4:  *
   5:  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
   6:  * 
   7:  * Project Info:  http://www.jfree.org/jcommon/index.html
   8:  *
   9:  * This library is free software; you can redistribute it and/or modify it 
  10:  * under the terms of the GNU Lesser General Public License as published by 
  11:  * the Free Software Foundation; either version 2.1 of the License, or 
  12:  * (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but 
  15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  16:  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
  17:  * License for more details.
  18:  *
  19:  * You should have received a copy of the GNU Lesser General Public
  20:  * License along with this library; if not, write to the Free Software
  21:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
  22:  * USA.  
  23:  *
  24:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
  25:  * in the United States and other countries.]
  26:  * 
  27:  * --------------------
  28:  * RectangleInsets.java
  29:  * --------------------
  30:  * (C) Copyright 2004, 2005, by Object Refinery Limited.
  31:  *
  32:  * Original Author:  David Gilbert (for Object Refinery Limited);
  33:  * Contributor(s):   -;
  34:  *
  35:  * $Id: RectangleInsets.java,v 1.14 2005/11/16 15:58:41 taqua Exp $
  36:  *
  37:  * Changes:
  38:  * --------
  39:  * 11-Feb-2004 : Version 1 (DG);
  40:  * 14-Jun-2004 : Implemented Serializable (DG);
  41:  * 02-Feb-2005 : Added new methods and renamed some existing methods (DG);
  42:  * 22-Feb-2005 : Added a new constructor for convenience (DG);
  43:  * 19-Apr-2005 : Changed order of parameters in constructors to match
  44:  *               java.awt.Insets (DG);
  45:  * 
  46:  */
  47: 
  48: package org.jfree.ui;
  49: 
  50: import java.awt.geom.Rectangle2D;
  51: import java.io.Serializable;
  52: 
  53: import org.jfree.util.UnitType;
  54: 
  55: /**
  56:  * Represents the insets for a rectangle, specified in absolute or relative 
  57:  * terms. This class is immutable.
  58:  *
  59:  * @author David Gilbert
  60:  */
  61: public class RectangleInsets implements Serializable {
  62: 
  63:     /** For serialization. */
  64:     private static final long serialVersionUID = 1902273207559319996L;
  65:     
  66:     /**
  67:      * A useful constant representing zero insets.
  68:      */
  69:     public static final RectangleInsets ZERO_INSETS = new RectangleInsets(
  70:         UnitType.ABSOLUTE, 0.0, 0.0, 0.0, 0.0);
  71:     
  72:     /** Absolute or relative units. */
  73:     private UnitType unitType;
  74:     
  75:     /** The top insets. */
  76:     private double top;
  77:     
  78:     /** The left insets. */
  79:     private double left;
  80:     
  81:     /** The bottom insets. */
  82:     private double bottom;
  83:     
  84:     /** The right insets. */
  85:     private double right;
  86:     
  87:     /**
  88:      * Creates a new instance with the specified insets (as 'absolute' units).
  89:      * 
  90:      * @param top  the top insets.
  91:      * @param left  the left insets.
  92:      * @param bottom  the bottom insets.
  93:      * @param right  the right insets.
  94:      */
  95:     public RectangleInsets(final double top, final double left,
  96:                            final double bottom, final double right) {
  97:         this(UnitType.ABSOLUTE, top, left, bottom, right);   
  98:     }
  99:     
 100:     /**
 101:      * Creates a new instance.
 102:      * 
 103:      * @param unitType  absolute or relative units (<code>null</code> not 
 104:      *                  permitted).
 105:      * @param top  the top insets.
 106:      * @param left  the left insets.
 107:      * @param bottom  the bottom insets.
 108:      * @param right  the right insets.
 109:      */
 110:     public RectangleInsets(final UnitType unitType,
 111:                            final double top, final double left, 
 112:                            final double bottom, final double right) {
 113:         if (unitType == null) {
 114:             throw new IllegalArgumentException("Null 'unitType' argument.");
 115:         }
 116:         this.unitType = unitType;
 117:         this.top = top;
 118:         this.bottom = bottom;
 119:         this.left = left;
 120:         this.right = right;
 121:     }
 122:     
 123:     /**
 124:      * Returns the unit type (absolute or relative).  This specifies whether 
 125:      * the insets are measured as Java2D units or percentages.
 126:      * 
 127:      * @return The unit type (never <code>null</code>).
 128:      */
 129:     public UnitType getUnitType() {
 130:         return this.unitType;
 131:     }
 132:   
 133:     /**
 134:      * Returns the top insets.
 135:      * 
 136:      * @return The top insets.
 137:      */
 138:     public double getTop() {
 139:         return this.top;
 140:     }
 141:     
 142:     /**
 143:      * Returns the bottom insets.
 144:      * 
 145:      * @return The bottom insets.
 146:      */
 147:     public double getBottom() {
 148:         return this.bottom;
 149:     }
 150:     
 151:     /**
 152:      * Returns the left insets.
 153:      * 
 154:      * @return The left insets.
 155:      */
 156:     public double getLeft() {
 157:         return this.left;
 158:     }
 159:     
 160:     /**
 161:      * Returns the right insets.
 162:      * 
 163:      * @return The right insets.
 164:      */
 165:     public double getRight() {
 166:         return this.right;
 167:     }
 168:     
 169:     /**
 170:      * Tests this instance for equality with an arbitrary object.
 171:      * 
 172:      * @param obj  the object (<code>null</code> permitted).
 173:      * 
 174:      * @return A boolean.
 175:      */
 176:     public boolean equals(final Object obj) {
 177:         if (obj == this) {
 178:             return true;   
 179:         }
 180:         if (!(obj instanceof RectangleInsets)) {
 181:                 return false;
 182:         }
 183:         final RectangleInsets that = (RectangleInsets) obj;
 184:         if (that.unitType != this.unitType) {
 185:             return false;   
 186:         }
 187:         if (this.left != that.left) {
 188:             return false;   
 189:         }
 190:         if (this.right != that.right) {
 191:             return false;   
 192:         }
 193:         if (this.top != that.top) {
 194:             return false;   
 195:         }
 196:         if (this.bottom != that.bottom) {
 197:             return false;   
 198:         }
 199:         return true;   
 200:     }
 201: 
 202:     /**
 203:      * Returns a hash code for the object.
 204:      * 
 205:      * @return A hash code.
 206:      */
 207:     public int hashCode() {
 208:         int result;
 209:         long temp;
 210:         result = (this.unitType != null ? this.unitType.hashCode() : 0);
 211:         temp = this.top != +0.0d ? Double.doubleToLongBits(this.top) : 0L;
 212:         result = 29 * result + (int) (temp ^ (temp >>> 32));
 213:         temp = this.bottom != +0.0d ? Double.doubleToLongBits(this.bottom) : 0L;
 214:         result = 29 * result + (int) (temp ^ (temp >>> 32));
 215:         temp = this.left != +0.0d ? Double.doubleToLongBits(this.left) : 0L;
 216:         result = 29 * result + (int) (temp ^ (temp >>> 32));
 217:         temp = this.right != +0.0d ? Double.doubleToLongBits(this.right) : 0L;
 218:         result = 29 * result + (int) (temp ^ (temp >>> 32));
 219:         return result;
 220:     }
 221: 
 222:     /**
 223:      * Returns a textual representation of this instance, useful for debugging
 224:      * purposes.
 225:      * 
 226:      * @return A string representing this instance.
 227:      */
 228:     public String toString() {
 229:         return "RectangleInsets[t=" + this.top + ",l=" + this.left
 230:                 + ",b=" + this.bottom + ",r=" + this.right + "]";
 231:     }
 232:     
 233:     /**
 234:      * Creates an adjusted rectangle using the supplied rectangle, the insets
 235:      * specified by this instance, and the horizontal and vertical 
 236:      * adjustment types.
 237:      * 
 238:      * @param base  the base rectangle (<code>null</code> not permitted).
 239:      * @param horizontal  the horizontal adjustment type (<code>null</code> not
 240:      *                    permitted).
 241:      * @param vertical  the vertical adjustment type (<code>null</code> not 
 242:      *                  permitted).
 243:      * 
 244:      * @return The inset rectangle.
 245:      */
 246:     public Rectangle2D createAdjustedRectangle(final Rectangle2D base,
 247:                                           final LengthAdjustmentType horizontal, 
 248:                                                   final LengthAdjustmentType vertical) {
 249:         if (base == null) {
 250:             throw new IllegalArgumentException("Null 'base' argument.");
 251:         }
 252:         double x = base.getX();
 253:         double y = base.getY();
 254:         double w = base.getWidth();
 255:         double h = base.getHeight();
 256:         if (horizontal == LengthAdjustmentType.EXPAND) {
 257:             final double leftOutset = calculateLeftOutset(w);
 258:             x = x - leftOutset;
 259:             w = w + leftOutset + calculateRightOutset(w);
 260:         }
 261:         else if (horizontal == LengthAdjustmentType.CONTRACT) {
 262:             final double leftMargin = calculateLeftInset(w);
 263:             x = x + leftMargin;
 264:             w = w - leftMargin - calculateRightInset(w);
 265:         }
 266:         if (vertical == LengthAdjustmentType.EXPAND) {
 267:             final double topMargin = calculateTopOutset(h);
 268:             y = y - topMargin;
 269:             h = h + topMargin + calculateBottomOutset(h);
 270:         }
 271:         else if (vertical == LengthAdjustmentType.CONTRACT) {
 272:             final double topMargin = calculateTopInset(h);
 273:             y = y + topMargin;
 274:             h = h - topMargin - calculateBottomInset(h);
 275:         }
 276:         return new Rectangle2D.Double(x, y, w, h);
 277:     }
 278:     
 279:     /**
 280:      * Creates an 'inset' rectangle.
 281:      * 
 282:      * @param base  the base rectangle (<code>null</code> not permitted).
 283:      * 
 284:      * @return The inset rectangle.
 285:      */
 286:     public Rectangle2D createInsetRectangle(final Rectangle2D base) {
 287:         return createInsetRectangle(base, true, true);
 288:     }
 289:     
 290:     /**
 291:      * Creates an 'inset' rectangle.
 292:      * 
 293:      * @param base  the base rectangle (<code>null</code> not permitted).
 294:      * @param horizontal  apply horizontal insets?
 295:      * @param vertical  apply vertical insets?
 296:      * 
 297:      * @return The inset rectangle.
 298:      */
 299:     public Rectangle2D createInsetRectangle(final Rectangle2D base,
 300:                                             final boolean horizontal, 
 301:                                             final boolean vertical) {
 302:         if (base == null) {
 303:             throw new IllegalArgumentException("Null 'base' argument.");
 304:         }
 305:         double topMargin = 0.0;
 306:         double bottomMargin = 0.0;
 307:         if (vertical) {
 308:             topMargin = calculateTopInset(base.getHeight());
 309:             bottomMargin = calculateBottomInset(base.getHeight());
 310:         }
 311:         double leftMargin = 0.0;
 312:         double rightMargin = 0.0;
 313:         if (horizontal) {
 314:             leftMargin = calculateLeftInset(base.getWidth());
 315:             rightMargin = calculateRightInset(base.getWidth());
 316:         }
 317:         return new Rectangle2D.Double(
 318:             base.getX() + leftMargin, 
 319:             base.getY() + topMargin,
 320:             base.getWidth() - leftMargin - rightMargin,
 321:             base.getHeight() - topMargin - bottomMargin
 322:         );
 323:     }
 324:     
 325:     /**
 326:      * Creates an outset rectangle.
 327:      * 
 328:      * @param base  the base rectangle (<code>null</code> not permitted).
 329:      * 
 330:      * @return An outset rectangle.
 331:      */
 332:     public Rectangle2D createOutsetRectangle(final Rectangle2D base) {
 333:         return createOutsetRectangle(base, true, true);
 334:     }
 335:     
 336:     /**
 337:      * Creates an outset rectangle.
 338:      * 
 339:      * @param base  the base rectangle (<code>null</code> not permitted).
 340:      * @param horizontal  apply horizontal insets?
 341:      * @param vertical  apply vertical insets? 
 342:      * 
 343:      * @return An outset rectangle.
 344:      */
 345:     public Rectangle2D createOutsetRectangle(final Rectangle2D base,
 346:                                              final boolean horizontal, 
 347:                                              final boolean vertical) {
 348:         if (base == null) {
 349:             throw new IllegalArgumentException("Null 'base' argument.");
 350:         }
 351:         double topMargin = 0.0;
 352:         double bottomMargin = 0.0;
 353:         if (vertical) {
 354:             topMargin = calculateTopOutset(base.getHeight());
 355:             bottomMargin = calculateBottomOutset(base.getHeight());
 356:         }
 357:         double leftMargin = 0.0;
 358:         double rightMargin = 0.0;
 359:         if (horizontal) {
 360:             leftMargin = calculateLeftOutset(base.getWidth());
 361:             rightMargin = calculateRightOutset(base.getWidth());
 362:         }
 363:         return new Rectangle2D.Double(
 364:             base.getX() - leftMargin, 
 365:             base.getY() - topMargin,
 366:             base.getWidth() + leftMargin + rightMargin,
 367:             base.getHeight() + topMargin + bottomMargin
 368:         );
 369:     }
 370:     
 371:     /**
 372:      * Returns the top margin.
 373:      * 
 374:      * @param height  the height of the base rectangle.
 375:      * 
 376:      * @return The top margin (in Java2D units).
 377:      */
 378:     public double calculateTopInset(final double height) {
 379:         double result = this.top;
 380:         if (this.unitType == UnitType.RELATIVE) {
 381:             result = (this.top * height);
 382:         }
 383:         return result;
 384:     }
 385:     
 386:     /**
 387:      * Returns the top margin.
 388:      * 
 389:      * @param height  the height of the base rectangle.
 390:      * 
 391:      * @return The top margin (in Java2D units).
 392:      */
 393:     public double calculateTopOutset(final double height) {
 394:         double result = this.top;
 395:         if (this.unitType == UnitType.RELATIVE) {
 396:             result = (height / (1 - this.top - this.bottom)) * this.top;
 397:         }
 398:         return result;
 399:     }
 400:     
 401:     /**
 402:      * Returns the bottom margin.
 403:      * 
 404:      * @param height  the height of the base rectangle.
 405:      * 
 406:      * @return The bottom margin (in Java2D units).
 407:      */
 408:     public double calculateBottomInset(final double height) {
 409:         double result = this.bottom;
 410:         if (this.unitType == UnitType.RELATIVE) {
 411:             result = (this.bottom * height);
 412:         }
 413:         return result;
 414:     }
 415: 
 416:     /**
 417:      * Returns the bottom margin.
 418:      * 
 419:      * @param height  the height of the base rectangle.
 420:      * 
 421:      * @return The bottom margin (in Java2D units).
 422:      */
 423:     public double calculateBottomOutset(final double height) {
 424:         double result = this.bottom;
 425:         if (this.unitType == UnitType.RELATIVE) {
 426:             result = (height / (1 - this.top - this.bottom)) * this.bottom;
 427:         }
 428:         return result;
 429:     }
 430: 
 431:     /**
 432:      * Returns the left margin.
 433:      * 
 434:      * @param width  the width of the base rectangle.
 435:      * 
 436:      * @return The left margin (in Java2D units).
 437:      */
 438:     public double calculateLeftInset(final double width) {
 439:         double result = this.left;
 440:         if (this.unitType == UnitType.RELATIVE) {
 441:             result = (this.left * width);
 442:         }
 443:         return result;
 444:     }
 445:     
 446:     /**
 447:      * Returns the left margin.
 448:      * 
 449:      * @param width  the width of the base rectangle.
 450:      * 
 451:      * @return The left margin (in Java2D units).
 452:      */
 453:     public double calculateLeftOutset(final double width) {
 454:         double result = this.left;
 455:         if (this.unitType == UnitType.RELATIVE) {
 456:             result = (width / (1 - this.left - this.right)) * this.left;
 457:         }
 458:         return result;
 459:     }
 460:     
 461:     /**
 462:      * Returns the right margin.
 463:      * 
 464:      * @param width  the width of the base rectangle.
 465:      * 
 466:      * @return The right margin (in Java2D units).
 467:      */
 468:     public double calculateRightInset(final double width) {
 469:         double result = this.right;
 470:         if (this.unitType == UnitType.RELATIVE) {
 471:             result = (this.right * width);
 472:         }
 473:         return result;
 474:     }
 475:     
 476:     /**
 477:      * Returns the right margin.
 478:      * 
 479:      * @param width  the width of the base rectangle.
 480:      * 
 481:      * @return The right margin (in Java2D units).
 482:      */
 483:     public double calculateRightOutset(final double width) {
 484:         double result = this.right;
 485:         if (this.unitType == UnitType.RELATIVE) {
 486:             result = (width / (1 - this.left - this.right)) * this.right;
 487:         }
 488:         return result;
 489:     }
 490:     
 491:     /**
 492:      * Trims the given width to allow for the insets.
 493:      * 
 494:      * @param width  the width.
 495:      * 
 496:      * @return The trimmed width.
 497:      */
 498:     public double trimWidth(final double width) {
 499:         return width - calculateLeftInset(width) - calculateRightInset(width);   
 500:     }
 501:     
 502:     /**
 503:      * Extends the given width to allow for the insets.
 504:      * 
 505:      * @param width  the width.
 506:      * 
 507:      * @return The extended width.
 508:      */
 509:     public double extendWidth(final double width) {
 510:         return width + calculateLeftOutset(width) + calculateRightOutset(width);   
 511:     }
 512: 
 513:     /**
 514:      * Trims the given height to allow for the insets.
 515:      * 
 516:      * @param height  the height.
 517:      * 
 518:      * @return The trimmed height.
 519:      */
 520:     public double trimHeight(final double height) {
 521:         return height 
 522:                - calculateTopInset(height) - calculateBottomInset(height);   
 523:     }
 524:     
 525:     /**
 526:      * Extends the given height to allow for the insets.
 527:      * 
 528:      * @param height  the height.
 529:      * 
 530:      * @return The extended height.
 531:      */
 532:     public double extendHeight(final double height) {
 533:         return height 
 534:                + calculateTopOutset(height) + calculateBottomOutset(height);   
 535:     }
 536: 
 537:     /**
 538:      * Shrinks the given rectangle by the amount of these insets.
 539:      * 
 540:      * @param area  the area (<code>null</code> not permitted).
 541:      */
 542:     public void trim(final Rectangle2D area) {
 543:         final double w = area.getWidth();
 544:         final double h = area.getHeight();
 545:         final double l = calculateLeftInset(w);
 546:         final double r = calculateRightInset(w);
 547:         final double t = calculateTopInset(h);
 548:         final double b = calculateBottomInset(h);
 549:         area.setRect(area.getX() + l, area.getY() + t, w - l - r, h - t - b);    
 550:     }
 551:     
 552: }