001: /* ========================================================================
002: * JCommon : a free general purpose class library for the Java(tm) platform
003: * ========================================================================
004: *
005: * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
006: *
007: * Project Info: http://www.jfree.org/jcommon/index.html
008: *
009: * This library is free software; you can redistribute it and/or modify it
010: * under the terms of the GNU Lesser General Public License as published by
011: * the Free Software Foundation; either version 2.1 of the License, or
012: * (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but
015: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017: * License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022: * USA.
023: *
024: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025: * in the United States and other countries.]
026: *
027: * --------------------
028: * RectangleInsets.java
029: * --------------------
030: * (C) Copyright 2004, 2005, 2007, by Object Refinery Limited.
031: *
032: * Original Author: David Gilbert (for Object Refinery Limited);
033: * Contributor(s): -;
034: *
035: * $Id: RectangleInsets.java,v 1.15 2007/03/16 14:29:45 mungady Exp $
036: *
037: * Changes:
038: * --------
039: * 11-Feb-2004 : Version 1 (DG);
040: * 14-Jun-2004 : Implemented Serializable (DG);
041: * 02-Feb-2005 : Added new methods and renamed some existing methods (DG);
042: * 22-Feb-2005 : Added a new constructor for convenience (DG);
043: * 19-Apr-2005 : Changed order of parameters in constructors to match
044: * java.awt.Insets (DG);
045: * 16-Mar-2007 : Added default constructor (DG);
046: *
047: */
048:
049: package org.jfree.ui;
050:
051: import java.awt.geom.Rectangle2D;
052: import java.io.Serializable;
053:
054: import org.jfree.util.UnitType;
055:
056: /**
057: * Represents the insets for a rectangle, specified in absolute or relative
058: * terms. This class is immutable.
059: *
060: * @author David Gilbert
061: */
062: public class RectangleInsets implements Serializable {
063:
064: /** For serialization. */
065: private static final long serialVersionUID = 1902273207559319996L;
066:
067: /**
068: * A useful constant representing zero insets.
069: */
070: public static final RectangleInsets ZERO_INSETS = new RectangleInsets(
071: UnitType.ABSOLUTE, 0.0, 0.0, 0.0, 0.0);
072:
073: /** Absolute or relative units. */
074: private UnitType unitType;
075:
076: /** The top insets. */
077: private double top;
078:
079: /** The left insets. */
080: private double left;
081:
082: /** The bottom insets. */
083: private double bottom;
084:
085: /** The right insets. */
086: private double right;
087:
088: /**
089: * Creates a new instance with all insets initialised to <code>1.0</code>.
090: *
091: * @since 1.0.9
092: */
093: public RectangleInsets() {
094: this (1.0, 1.0, 1.0, 1.0);
095: }
096:
097: /**
098: * Creates a new instance with the specified insets (as 'absolute' units).
099: *
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, final double top,
121: final double left, final double bottom, final double right) {
122: if (unitType == null) {
123: throw new IllegalArgumentException(
124: "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)
222: : 0L;
223: result = 29 * result + (int) (temp ^ (temp >>> 32));
224: temp = this .bottom != +0.0d ? Double
225: .doubleToLongBits(this .bottom) : 0L;
226: result = 29 * result + (int) (temp ^ (temp >>> 32));
227: temp = this .left != +0.0d ? Double.doubleToLongBits(this .left)
228: : 0L;
229: result = 29 * result + (int) (temp ^ (temp >>> 32));
230: temp = this .right != +0.0d ? Double
231: .doubleToLongBits(this .right) : 0L;
232: result = 29 * result + (int) (temp ^ (temp >>> 32));
233: return result;
234: }
235:
236: /**
237: * Returns a textual representation of this instance, useful for debugging
238: * purposes.
239: *
240: * @return A string representing this instance.
241: */
242: public String toString() {
243: return "RectangleInsets[t=" + this .top + ",l=" + this .left
244: + ",b=" + this .bottom + ",r=" + this .right + "]";
245: }
246:
247: /**
248: * Creates an adjusted rectangle using the supplied rectangle, the insets
249: * specified by this instance, and the horizontal and vertical
250: * adjustment types.
251: *
252: * @param base the base rectangle (<code>null</code> not permitted).
253: * @param horizontal the horizontal adjustment type (<code>null</code> not
254: * permitted).
255: * @param vertical the vertical adjustment type (<code>null</code> not
256: * permitted).
257: *
258: * @return The inset rectangle.
259: */
260: public Rectangle2D createAdjustedRectangle(final Rectangle2D base,
261: final LengthAdjustmentType horizontal,
262: final LengthAdjustmentType vertical) {
263: if (base == null) {
264: throw new IllegalArgumentException("Null 'base' argument.");
265: }
266: double x = base.getX();
267: double y = base.getY();
268: double w = base.getWidth();
269: double h = base.getHeight();
270: if (horizontal == LengthAdjustmentType.EXPAND) {
271: final double leftOutset = calculateLeftOutset(w);
272: x = x - leftOutset;
273: w = w + leftOutset + calculateRightOutset(w);
274: } else if (horizontal == LengthAdjustmentType.CONTRACT) {
275: final double leftMargin = calculateLeftInset(w);
276: x = x + leftMargin;
277: w = w - leftMargin - calculateRightInset(w);
278: }
279: if (vertical == LengthAdjustmentType.EXPAND) {
280: final double topMargin = calculateTopOutset(h);
281: y = y - topMargin;
282: h = h + topMargin + calculateBottomOutset(h);
283: } else if (vertical == LengthAdjustmentType.CONTRACT) {
284: final double topMargin = calculateTopInset(h);
285: y = y + topMargin;
286: h = h - topMargin - calculateBottomInset(h);
287: }
288: return new Rectangle2D.Double(x, y, w, h);
289: }
290:
291: /**
292: * Creates an 'inset' rectangle.
293: *
294: * @param base the base rectangle (<code>null</code> not permitted).
295: *
296: * @return The inset rectangle.
297: */
298: public Rectangle2D createInsetRectangle(final Rectangle2D base) {
299: return createInsetRectangle(base, true, true);
300: }
301:
302: /**
303: * Creates an 'inset' rectangle.
304: *
305: * @param base the base rectangle (<code>null</code> not permitted).
306: * @param horizontal apply horizontal insets?
307: * @param vertical apply vertical insets?
308: *
309: * @return The inset rectangle.
310: */
311: public Rectangle2D createInsetRectangle(final Rectangle2D base,
312: final boolean horizontal, final boolean vertical) {
313: if (base == null) {
314: throw new IllegalArgumentException("Null 'base' argument.");
315: }
316: double topMargin = 0.0;
317: double bottomMargin = 0.0;
318: if (vertical) {
319: topMargin = calculateTopInset(base.getHeight());
320: bottomMargin = calculateBottomInset(base.getHeight());
321: }
322: double leftMargin = 0.0;
323: double rightMargin = 0.0;
324: if (horizontal) {
325: leftMargin = calculateLeftInset(base.getWidth());
326: rightMargin = calculateRightInset(base.getWidth());
327: }
328: return new Rectangle2D.Double(base.getX() + leftMargin, base
329: .getY()
330: + topMargin,
331: base.getWidth() - leftMargin - rightMargin, base
332: .getHeight()
333: - topMargin - bottomMargin);
334: }
335:
336: /**
337: * Creates an outset rectangle.
338: *
339: * @param base the base rectangle (<code>null</code> not permitted).
340: *
341: * @return An outset rectangle.
342: */
343: public Rectangle2D createOutsetRectangle(final Rectangle2D base) {
344: return createOutsetRectangle(base, true, true);
345: }
346:
347: /**
348: * Creates an outset rectangle.
349: *
350: * @param base the base rectangle (<code>null</code> not permitted).
351: * @param horizontal apply horizontal insets?
352: * @param vertical apply vertical insets?
353: *
354: * @return An outset rectangle.
355: */
356: public Rectangle2D createOutsetRectangle(final Rectangle2D base,
357: final boolean horizontal, 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(base.getX() - leftMargin, base
374: .getY()
375: - topMargin,
376: base.getWidth() + leftMargin + rightMargin, base
377: .getHeight()
378: + topMargin + bottomMargin);
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))
437: * this .bottom;
438: }
439: return result;
440: }
441:
442: /**
443: * Returns the left margin.
444: *
445: * @param width the width of the base rectangle.
446: *
447: * @return The left margin (in Java2D units).
448: */
449: public double calculateLeftInset(final double width) {
450: double result = this .left;
451: if (this .unitType == UnitType.RELATIVE) {
452: result = (this .left * width);
453: }
454: return result;
455: }
456:
457: /**
458: * Returns the left margin.
459: *
460: * @param width the width of the base rectangle.
461: *
462: * @return The left margin (in Java2D units).
463: */
464: public double calculateLeftOutset(final double width) {
465: double result = this .left;
466: if (this .unitType == UnitType.RELATIVE) {
467: result = (width / (1 - this .left - this .right)) * this .left;
468: }
469: return result;
470: }
471:
472: /**
473: * Returns the right margin.
474: *
475: * @param width the width of the base rectangle.
476: *
477: * @return The right margin (in Java2D units).
478: */
479: public double calculateRightInset(final double width) {
480: double result = this .right;
481: if (this .unitType == UnitType.RELATIVE) {
482: result = (this .right * width);
483: }
484: return result;
485: }
486:
487: /**
488: * Returns the right margin.
489: *
490: * @param width the width of the base rectangle.
491: *
492: * @return The right margin (in Java2D units).
493: */
494: public double calculateRightOutset(final double width) {
495: double result = this .right;
496: if (this .unitType == UnitType.RELATIVE) {
497: result = (width / (1 - this .left - this .right))
498: * this .right;
499: }
500: return result;
501: }
502:
503: /**
504: * Trims the given width to allow for the insets.
505: *
506: * @param width the width.
507: *
508: * @return The trimmed width.
509: */
510: public double trimWidth(final double width) {
511: return width - calculateLeftInset(width)
512: - calculateRightInset(width);
513: }
514:
515: /**
516: * Extends the given width to allow for the insets.
517: *
518: * @param width the width.
519: *
520: * @return The extended width.
521: */
522: public double extendWidth(final double width) {
523: return width + calculateLeftOutset(width)
524: + calculateRightOutset(width);
525: }
526:
527: /**
528: * Trims the given height to allow for the insets.
529: *
530: * @param height the height.
531: *
532: * @return The trimmed height.
533: */
534: public double trimHeight(final double height) {
535: return height - calculateTopInset(height)
536: - calculateBottomInset(height);
537: }
538:
539: /**
540: * Extends the given height to allow for the insets.
541: *
542: * @param height the height.
543: *
544: * @return The extended height.
545: */
546: public double extendHeight(final double height) {
547: return height + calculateTopOutset(height)
548: + calculateBottomOutset(height);
549: }
550:
551: /**
552: * Shrinks the given rectangle by the amount of these insets.
553: *
554: * @param area the area (<code>null</code> not permitted).
555: */
556: public void trim(final Rectangle2D area) {
557: final double w = area.getWidth();
558: final double h = area.getHeight();
559: final double l = calculateLeftInset(w);
560: final double r = calculateRightInset(w);
561: final double t = calculateTopInset(h);
562: final double b = calculateBottomInset(h);
563: area.setRect(area.getX() + l, area.getY() + t, w - l - r, h - t
564: - b);
565: }
566:
567: }
|