001: /**
002: * Chart2D, a java library for drawing two dimensional charts.
003: * Copyright (C) 2001 Jason J. Simas
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: *
018: * The author of this library may be contacted at:
019: * E-mail: jjsimas@users.sourceforge.net
020: * Street Address: J J Simas, 887 Tico Road, Ojai, CA 93023-3555 USA
021: */package net.sourceforge.chart2d;
022:
023: import java.awt.*;
024:
025: /**
026: * A bordered area with a title and auto calculations for left over space. This
027: * class uses all the customizability of the bordered area class, adds a text
028: * area for the title, automatic gap below title functionality and title within
029: * area justification. The title can be located at the top, bottom, left or
030: * right, and sometimes centered. With
031: * any of these scenarios, the title can be rotated left. The left over space
032: * will be computed and is availabe through a get method.<br>
033: * Note: Do not pass any null values; instead pass an empty string if need be.
034: */
035: class TitledArea extends FontArea {
036:
037: private boolean titleAutoLocate;
038: private boolean titleExistence;
039: private TextArea title;
040: private Rectangle maxEntitledSpaceBounds;
041: private Rectangle minEntitledSpaceBounds;
042: private Color titleBackgroundColor;
043: private boolean betweenTitleAndSpaceGapExistence;
044: private int betweenTitleAndSpaceGapThicknessModel;
045: private int betweenTitleAndSpaceGapThickness;
046: private Dimension minUsedSpaceSize;
047: private boolean needsUpdate;
048:
049: /**
050: * Creates a new titled area with the default values:<br>
051: * setTitleExistence (true);<br>
052: * setFontPointModel (14);<br>
053: * setBetweenTitleAndSpaceGapExistence (true);<br>
054: * setBetweenTitleAndSpaceGapThicknessModel (5);<br>
055: * setTitleJustifications (CENTER, TOP);<br>
056: * setTitleAutoLocate (true);<br>
057: * title.setAutoJustifys (false, false);<br>
058: * title.setBorderExistences (false, false, false, false);<br>
059: * title.setGapExistences (false, false, false, false);<br>
060: * title.setBackgroundExistence (false);<br>
061: * resetTitledAreaModel (true);<br>
062: */
063: TitledArea() {
064:
065: title = new TextArea();
066: maxEntitledSpaceBounds = new Rectangle();
067: minEntitledSpaceBounds = new Rectangle();
068:
069: setTitleExistence(true);
070: setFontPointModel(14);
071: setBetweenTitleAndSpaceGapExistence(true);
072: setBetweenTitleAndSpaceGapThicknessModel(5);
073: setTitleJustifications(CENTER, TOP);
074: setTitleAutoLocate(true);
075:
076: title.setAutoJustifys(false, false);
077: title.setBorderExistences(false, false, false, false);
078: title.setGapExistences(false, false, false, false);
079: title.setBackgroundExistence(false);
080: resetTitledAreaModel(true);
081: needsUpdate = true;
082: }
083:
084: /**
085: * Changes the existence of the title; whether the title exists or not.
086: * Otherwise, title will not be included in calculations and will not be
087: * painted.
088: * @param existence If true, then title exists.
089: */
090: final void setTitleExistence(boolean existence) {
091:
092: needsUpdate = true;
093: titleExistence = existence;
094: }
095:
096: /**
097: * Changes the text of the title.
098: * @param title The new text of this title.
099: */
100: final void setTitle(String title) {
101:
102: needsUpdate = true;
103: this .title.setText(title);
104: }
105:
106: /**
107: * Changes whether the title will locate itself automatically within
108: * the area according to the title justifications. Otherwise, the title
109: * location must be set manually using the title set location method.
110: * @param auto true if the title will locate itself
111: */
112: final void setTitleAutoLocate(boolean auto) {
113:
114: needsUpdate = true;
115: titleAutoLocate = auto;
116: }
117:
118: /**
119: * Changes the location of the title. The top, left part of the title
120: * no matter what title orientation.
121: * @param location The top left part of the title's location.
122: */
123: final void setTitleLocation(Point location) {
124:
125: needsUpdate = true;
126: title.setSpaceSizeLocation(MIN, location);
127: }
128:
129: /**
130: * Changes whether this title should be rotated left of not.
131: * When rotating left, the text will be rotated -90 degrees. However, the
132: * origin and the size of the label will not be rotated. It will encapsulate
133: * the newly rotated text.
134: * @param rotate If true, then text will be rotated -90 degrees whenever
135: * painted. However, values are updated immediately.
136: */
137: final void setTitleRotateLeft(boolean rotate) {
138:
139: needsUpdate = true;
140: title.setRotateLeft(rotate);
141: }
142:
143: /**
144: * Specifies the horizontal and vertical justification for the title text
145: * respective to the size of the area. Note: A non rotated title cannot
146: * be vertically centered. And a rotated title cannot be horizontally
147: * centered.
148: * @param horizontal How to justify the title horizontally. Possible values
149: * area LEFT, RIGHT, and CENTER.
150: * [see note above for more detail about centering]
151: * @param vertical How to justify the title vertically. Possible values area
152: * TOP, BOTTOM, and CENTER. [see note above for more detail about centering]
153: */
154: final void setTitleJustifications(int horizontal, int vertical) {
155:
156: needsUpdate = true;
157: title.setJustifications(horizontal, vertical);
158: }
159:
160: /**
161: * Specifies whether there should exist a gap between title and the available
162: * space. Part of the functionality of this class is to calculate space not
163: * used by the title. Setting this gap, makes the available space less so
164: * drawing can begin exactly in the space, and look good becuase its spaced
165: * nicely from the title.
166: * @param existence If true, then gap is subtracted from space; else gap model
167: * thickness is ignored.
168: */
169: final void setBetweenTitleAndSpaceGapExistence(boolean existence) {
170:
171: needsUpdate = true;
172: betweenTitleAndSpaceGapExistence = existence;
173: }
174:
175: /**
176: * Specifies how large the model gap should be. Part of the functionality of
177: * this class is to calculate space not
178: * used by the title. This gap, makes the available space less so
179: * drawing can begin exactly in the space, and look good becuase its spaced
180: * nicely from the title.
181: * @param gap The thickness of the model gap. If model max size autosizing is
182: * disabled, then a ratio based on max size / model max size will be applied
183: * to this thickness to obtain the actual thickness; otherwise, the thickness
184: * will be this model thickness. Also, if gap existence is false, this
185: * thickness will be ignored.
186: */
187: final void setBetweenTitleAndSpaceGapThicknessModel(int gap) {
188:
189: needsUpdate = true;
190: betweenTitleAndSpaceGapThicknessModel = gap;
191: }
192:
193: /**
194: * Returns the model gap thickness between the title and the bounds.
195: * @return The thickness of the model gap.
196: */
197: final int getBetweenTitleAndSpaceGapThicknessModel() {
198:
199: return betweenTitleAndSpaceGapThicknessModel;
200: }
201:
202: /**
203: * Returns the available space and location of that space. The available
204: * space is the area less the title and the gap. Updates all variables
205: * before calculating the bounds.
206: * @param g2D The graphics context for calculations and painting.
207: * @return The bounds of the available space.
208: */
209: final Rectangle getMaxEntitledSpaceBounds(Graphics2D g2D) {
210:
211: updateTitledArea(g2D);
212: return maxEntitledSpaceBounds;
213: }
214:
215: /**
216: * Returns the available space and location of that space. The available
217: * space is the area less the title and the gap. Updates all variables
218: * before calculating the bounds.
219: * @param g2D The graphics context for calculations and painting.
220: * @return The bounds of the available space.
221: */
222: final Rectangle getMinEntitledSpaceBounds(Graphics2D g2D) {
223: updateTitledArea(g2D);
224: return minEntitledSpaceBounds;
225: }
226:
227: /**
228: * Returns the existence of the title; whether the title exists or not.
229: * @return If true, then title exists.
230: */
231: final boolean getTitleExistence() {
232:
233: return titleExistence;
234: }
235:
236: /**
237: * Gets the text of the title.
238: * @return The new text of this title.
239: */
240: final String getTitleText() {
241:
242: return title.getText();
243: }
244:
245: /**
246: * Gets the title.
247: * @return The title's TextArea.
248: */
249: final TextArea getTitle() {
250: return title;
251: }
252:
253: /**
254: * Returns the size of this title. Even if the title is rotated, the width
255: * of this dimension will correspond to width on the monitor screen, and
256: * not height. The same is true for the height of the dimension.
257: * @return The size of the title.
258: * @param which Which size MAXMODEL, MAX, or MIN.
259: * @param g2D The graphics context for calculations and painting.
260: */
261: final Dimension getTitleSize(int which, Graphics2D g2D) {
262:
263: updateTitledArea(g2D);
264: return title.getSize(which);
265: }
266:
267: /**
268: * Returns the horizontal or vertical justification of this title within the
269: * area.
270: * @param which Which type of justification to return. Possible values are
271: * HORIZONTAL and VERTICAL.
272: * @return The justification of this title. Possible values of
273: * horizontal justification area LEFT, RIGHT, and CENTER. Possible values of
274: * vertical justification are TOP, BOTTOM, and CENTER.
275: */
276: final int getTitleJustifications(int which) {
277:
278: return title.getJustifications(which);
279: }
280:
281: /**
282: * Indicates whether the title will locate itself automatically within
283: * the area according to the title justifications. Otherwise, the title
284: * location must be set manually using the title set location method.
285: * @return True if the title will locate itself
286: */
287: final boolean getTitleAutoLocate() {
288:
289: return titleAutoLocate;
290: }
291:
292: /**
293: * Returns the gap between the title and the available space. This is not
294: * the model gap thickness but the actual thickness, after applying the ratio
295: * when relevant. All variables area updated before returning this size.
296: * @param g2D The graphics context to use for calculations.
297: * @return The thickness of the gap between the title and the available space.
298: */
299: final int getBetweenTitleAndSpaceGapThickness(Graphics2D g2D) {
300:
301: updateTitledArea(g2D);
302: return betweenTitleAndSpaceGapThickness;
303: }
304:
305: /**
306: * Indicates whether some property of this class has changed.
307: * @return True if some property has changed.
308: */
309: final boolean getTitledAreaNeedsUpdate() {
310:
311: return (needsUpdate || getFontAreaNeedsUpdate());
312: }
313:
314: /**
315: * Updates all the variables in this parent's classes, then all of this'
316: * variables.
317: * @param g2D The graphics context to use for calculations.
318: */
319: final void updateTitledArea(Graphics2D g2D) {
320:
321: if (getTitledAreaNeedsUpdate()) {
322: updateFontArea();
323: update(g2D);
324: }
325: needsUpdate = false;
326: }
327:
328: /**
329: * Resets the model for this class. The model is used for shrinking and
330: * growing of its components based on the maximum size of this class. If this
331: * method is called, then the next time the maximum size is set, this classes
332: * model maximum size will be made equal to the new maximum size. Effectively
333: * what this does is ensure that whenever this objects maximum size is equal
334: * to the one given, then all of the components will take on their default
335: * model sizes. Note: This is only useful when auto model max sizing is
336: * disabled.
337: * @param reset True sets the max model size on the next max sizing.
338: */
339: final void resetTitledAreaModel(boolean reset) {
340:
341: needsUpdate = true;
342: resetFontAreaModel(reset);
343: title.resetTextAreaModel(reset);
344: }
345:
346: /**
347: * Paints all the components of this class. First all variables are updated.
348: * @param g2D The graphics context for calculations and painting.
349: */
350: void paintComponent(Graphics2D g2D) {
351:
352: updateTitledArea(g2D);
353: super .paintComponent(g2D);
354: title.paintComponent(g2D);
355: }
356:
357: private void update(Graphics2D g2D) {
358: updateMaxTitle();
359: title.updateTextArea(g2D);
360: updateGap();
361: updateMaxBounds(g2D);
362: updateMinBounds(g2D);
363: updateMinTitle();
364: }
365:
366: private void updateMaxTitle() {
367:
368: if (titleExistence) {
369: title.setCustomRatio(WIDTH, true, getRatio(WIDTH));
370: title.setCustomRatio(HEIGHT, true, getRatio(HEIGHT));
371: title.setAutoSizes(getAutoSize(MAXMODEL), false);
372: title.setSizeLocation(MAX, new Point(
373: getSpaceSizeLocation(MAX).x,
374: getSpaceSizeLocation(MAX).y));
375: Dimension titleSize = new Dimension(
376: getSpaceSize(MAX).width, getSpaceSize(MAX).height);
377: title.setSize(MAX, titleSize);
378: title.setFontPointModel(getFontPointModel());
379: title.setFontColor(getFontColor());
380: title.setFontName(getFont().getName());
381: title.setFontStyle(getFont().getStyle());
382: } else
383: title.setSize(MAX, new Dimension());
384: }
385:
386: private void updateGap() {
387:
388: if (betweenTitleAndSpaceGapExistence) {
389:
390: float ratio;
391: int available;
392: if (!title.getRotateLeft()) {
393: ratio = getRatio(HEIGHT);
394: available = getSpaceSize(MAX).height
395: - title.getSize(MIN).height;
396: } else {
397: ratio = getRatio(WIDTH);
398: available = getSpaceSize(MAX).width
399: - title.getSize(MIN).width;
400: }
401:
402: if (titleExistence && title.getSize(MIN).width > 0
403: && title.getSize(MIN).height > 0) {
404: betweenTitleAndSpaceGapThickness = applyRatio(
405: betweenTitleAndSpaceGapThicknessModel, ratio);
406: betweenTitleAndSpaceGapThickness = betweenTitleAndSpaceGapThickness < available ? betweenTitleAndSpaceGapThickness
407: : available;
408: } else
409: betweenTitleAndSpaceGapThickness = 0;
410: }
411:
412: else
413: betweenTitleAndSpaceGapThickness = 0;
414: }
415:
416: private void updateMaxBounds(Graphics2D g2D) {
417:
418: int spaceX;
419: int spaceY;
420: int spaceWidth;
421: int spaceHeight;
422: if (!title.getRotateLeft()) {
423: spaceX = getSpaceSizeLocation(MAX).x;
424: spaceWidth = getSpaceSize(MAX).width;
425: spaceHeight = getSpaceSize(MAX).height
426: - (title.getSize(MIN).height + betweenTitleAndSpaceGapThickness);
427: if (title.getJustifications(VERTICAL) == TOP) {
428: spaceY = getSpaceSizeLocation(MAX).y
429: + title.getSize(MIN).height
430: + betweenTitleAndSpaceGapThickness;
431: } else
432: spaceY = getSpaceSizeLocation(MAX).y;
433: } else {
434: spaceY = getSpaceSizeLocation(MAX).y;
435: spaceWidth = getSpaceSize(MAX).width
436: - (title.getSize(MIN).width + betweenTitleAndSpaceGapThickness);
437: spaceHeight = getSpaceSize(MAX).height;
438: if (title.getJustifications(HORIZONTAL) == LEFT) {
439: spaceX = getSpaceSizeLocation(MAX).x
440: + title.getSize(MIN).width
441: + betweenTitleAndSpaceGapThickness;
442: } else
443: spaceX = getSpaceSizeLocation(MAX).x;
444: }
445: maxEntitledSpaceBounds.setBounds(spaceX, spaceY, spaceWidth,
446: spaceHeight);
447: }
448:
449: private void updateMinBounds(Graphics2D g2D) {
450:
451: int spaceX;
452: int spaceY;
453: int spaceWidth;
454: int spaceHeight;
455: if (!title.getRotateLeft()) {
456: spaceX = getSpaceSizeLocation(MIN).x;
457: spaceWidth = getSpaceSize(MIN).width;
458: spaceHeight = getSpaceSize(MIN).height
459: - (title.getSize(MIN).height + betweenTitleAndSpaceGapThickness);
460: if (title.getJustifications(VERTICAL) == TOP) {
461: spaceY = getSpaceSizeLocation(MIN).y
462: + title.getSize(MIN).height
463: + betweenTitleAndSpaceGapThickness;
464: } else
465: spaceY = getSpaceSizeLocation(MIN).y;
466: } else {
467: spaceY = getSpaceSizeLocation(MIN).y;
468: spaceWidth = getSpaceSize(MIN).width
469: - (title.getSize(MIN).width + betweenTitleAndSpaceGapThickness);
470: spaceHeight = getSpaceSize(MIN).height;
471: if (title.getJustifications(HORIZONTAL) == LEFT) {
472: spaceX = getSpaceSizeLocation(MIN).x
473: + title.getSize(MIN).width
474: + betweenTitleAndSpaceGapThickness;
475: } else
476: spaceX = getSpaceSizeLocation(MIN).x;
477: }
478: minEntitledSpaceBounds.setBounds(spaceX, spaceY, spaceWidth,
479: spaceHeight);
480: }
481:
482: private void updateMinTitle() {
483:
484: if (titleAutoLocate) {
485:
486: int betweenWidth = title.getSizeLocation(MIN).x
487: - title.getSpaceSizeLocation(MIN).x;
488: int spaceX;
489: if (title.getJustifications(HORIZONTAL) == LEFT) {
490: spaceX = getSpaceSizeLocation(MIN).x + betweenWidth;
491: } else if (title.getJustifications(HORIZONTAL) == RIGHT) {
492: spaceX = getSpaceSizeLocation(MIN).x
493: + getSpaceSize(MIN).width
494: - title.getSpaceSize(MIN).width - betweenWidth;
495: } else {
496: spaceX = getSpaceSizeLocation(MIN).x
497: + (getSpaceSize(MIN).width - title
498: .getSpaceSize(MIN).width) / 2;
499: }
500:
501: int betweenHeight = title.getSpaceSizeLocation(MIN).y
502: - title.getSizeLocation(MIN).y;
503: int spaceY;
504: if (title.getJustifications(VERTICAL) == TOP) {
505: spaceY = getSpaceSizeLocation(MIN).y + betweenHeight;
506: } else if (title.getJustifications(VERTICAL) == BOTTOM) {
507: spaceY = getSpaceSizeLocation(MIN).y
508: + getSpaceSize(MIN).height
509: - title.getSpaceSize(MIN).height
510: - betweenHeight;
511: } else {
512: spaceY = getSpaceSizeLocation(MIN).y
513: + (getSpaceSize(MIN).height - title
514: .getSpaceSize(MIN).height) / 2;
515: }
516: title.setSpaceSizeLocation(MIN, new Point(spaceX, spaceY));
517: }
518: }
519: }
|