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