1 /*
2  *******************************************************************************
3  * Copyright (C) 1997-2010, International Business Machines Corporation and    *
4  * others. All Rights Reserved.                                                *
5  *******************************************************************************
6  */
7 package com.ibm.icu.dev.demo.holiday;
8 
9 import java.awt.Color;
10 import java.awt.Dimension;
11 import java.awt.Font;
12 import java.awt.FontMetrics;
13 import java.awt.Graphics;
14 import java.awt.Insets;
15 import java.awt.Panel;
16 
17 /**
18  * Various graphical borders. The border itself is a Panel so that it can
19  * contain other Components (i.e. it borders something). You use the
20  * HolidayBorderPanel like any other Panel: you set the layout that you prefer and
21  * add Components to it. Beware that a null layout does not obey the insets
22  * of the panel so if you use null layouts, adjust your measurements to
23  * handle the border by calling insets().
24  *
25  * @author  Andy Clark, Taligent Inc.
26  * @version 1.0
27  */
28 public class HolidayBorderPanel extends Panel {
29     /**
30      * For serialization
31      */
32     private static final long serialVersionUID = 4669213306492461159L;
33     // Constants
34 
35     /** Solid border. */
36     public final static int SOLID = 0;
37     /** A raised border. */
38     public final static int RAISED = 1;
39     /** A lowered border. */
40     public final static int LOWERED = 2;
41     /** An etched in border. */
42     public final static int IN = 3;
43     /** An etched out border. */
44     public final static int OUT = 4;
45 
46     /** Left alignment. */
47     public final static int LEFT = 0;
48     /** Center alignment. */
49     public final static int CENTER = 1;
50     /** Right alignment. */
51     public final static int RIGHT = 2;
52 
53     /** Default style (IN). */
54     public final static int DEFAULT_STYLE = IN;
55     /** Default thickness (10). */
56     public final static int DEFAULT_THICKNESS = 10;
57     /** Default thickness for solid borders (4). */
58     public final static int DEFAULT_SOLID_THICKNESS = 4;
59     /** Default thickness for raised borders (2). */
60     public final static int DEFAULT_RAISED_THICKNESS = 2;
61     /** Default thickness for lowered borders (2). */
62     public final static int DEFAULT_LOWERED_THICKNESS = 2;
63     /** Default thickness for etched-in borders (10). */
64     public final static int DEFAULT_IN_THICKNESS = 10;
65     /** Default thickness for etched-out borders (10). */
66     public final static int DEFAULT_OUT_THICKNESS = 10;
67     /** Default gap between border and contained component (5). */
68     public final static int DEFAULT_GAP = 5;
69     /** Default color (black). Applies to SOLID and etched borders. */
70     public final static Color DEFAULT_COLOR = Color.black;
71 
72     /** Default font (TimesRoman,PLAIN,14). Only applies to etched borders. */
73     public final static Font DEFAULT_FONT = new Font("TimesRoman", Font.PLAIN, 14);
74     /** Default alignment (LEFT). Only applies to etched borders. */
75     public final static int DEFAULT_ALIGNMENT = LEFT;
76 
77     // Data
78     private int style;
79     private int thickness;
80     private int gap;
81     private Color color;
82 
83     private Font font;
84     private String text;
85     private int alignment;
86 
87     /**
88      * Constructor. Makes default border.
89      */
HolidayBorderPanel()90     public HolidayBorderPanel() {
91 
92         // initialize data
93         style       = DEFAULT_STYLE;
94         thickness   = DEFAULT_THICKNESS;
95         gap         = DEFAULT_GAP;
96         color       = DEFAULT_COLOR;
97 
98         text        = null;
99         font        = DEFAULT_FONT;
100         alignment   = DEFAULT_ALIGNMENT;
101 
102         }
103 
104     /**
105      * Constructor. Makes an etched IN border with given text caption.
106      *
107      * @param text  Text caption
108      */
HolidayBorderPanel(String text)109     public HolidayBorderPanel(String text) {
110         this();
111 
112         style = IN;
113         this.text = text;
114         }
115 
116     /**
117      * Constructor. Makes SOLID border with color and thickness given.
118      *
119      * @param color     The color for the border.
120      * @param thickness The thickness of the border.
121      */
HolidayBorderPanel(Color color, int thickness)122     public HolidayBorderPanel(Color color, int thickness) {
123         this();
124 
125         style = SOLID;
126         this.color = color;
127         this.thickness = thickness;
128         }
129 
130     /**
131      * Constructor. Makes a border of the given style with the default
132      * thickness for that style.
133      *
134      * @param style The style for this border.
135      */
HolidayBorderPanel(int style)136     public HolidayBorderPanel(int style) {
137         this();
138 
139         // set thickness appropriate to this style
140         switch (style) {
141             case SOLID: thickness = DEFAULT_SOLID_THICKNESS; break;
142             case RAISED: thickness = DEFAULT_RAISED_THICKNESS; break;
143             case LOWERED: thickness = DEFAULT_LOWERED_THICKNESS; break;
144             case IN: thickness = DEFAULT_IN_THICKNESS; break;
145             case OUT: thickness = DEFAULT_OUT_THICKNESS; break;
146             default:
147                 thickness = DEFAULT_THICKNESS;
148             }
149 
150         this.style = style;
151         }
152 
153     /**
154      * Constructor. Makes border with given style and thickness.
155      *
156      * @param style     The style for this border.
157      * @param thickness The thickness for this border.
158      */
HolidayBorderPanel(int style, int thickness)159     public HolidayBorderPanel(int style, int thickness) {
160         this();
161 
162         this.style = style;
163         this.thickness = thickness;
164         }
165 
166     /**
167      * Returns the insets of this panel..
168      */
getInsets()169     public Insets getInsets() {
170         int adjustment = 0;
171 
172         // adjust for text string
173         if (style == IN || style == OUT) {
174             if (text != null && text.length() > 0) {
175                 try {
176                     // set font and get info
177                     int height = getGraphics().getFontMetrics(font).getHeight();
178                     if (height > thickness)
179                         adjustment = height - thickness;
180                     }
181                 catch (Exception e) {
182                     // nothing: just in case there is no graphics context
183                     //   at the beginning.
184                     System.out.print("");
185                     }
186                 }
187             }
188 
189         // return appropriate insets
190         int dist = thickness + gap;
191         return new Insets(dist + adjustment, dist, dist, dist);
192         }
193 
194     /**
195      * Sets the style of the border
196      *
197      * @param style The new style.
198      */
setStyle(int style)199     public HolidayBorderPanel setStyle(int style) {
200 
201         // set the style and re-layout the panel
202         this.style = style;
203         doLayout();
204         repaint();
205 
206         return this;
207         }
208 
209     /**
210      * Gets the style of the border
211      */
getStyle()212     public int getStyle() {
213 
214         return style;
215         }
216 
217     /**
218      * Sets the thickness of the border.
219      *
220      * @param thickness The new thickness
221      */
setThickness(int thickness)222     public HolidayBorderPanel setThickness(int thickness) {
223 
224         if (thickness > 0) {
225             this.thickness = thickness;
226             doLayout();
227             repaint();
228             }
229 
230         return this;
231         }
232 
233     /**
234      * Gets the thickness of the border.
235      */
getThickness()236     public int getThickness() {
237 
238         return thickness;
239         }
240 
241     /**
242      * Sets the gap between the border and the contained Component.
243      *
244      * @param gap The new gap, in pixels.
245      */
setGap(int gap)246     public HolidayBorderPanel setGap(int gap) {
247 
248         if (gap > -1) {
249             this.gap = gap;
250             doLayout();
251             repaint();
252             }
253 
254         return this;
255         }
256 
257     /**
258      * Gets the gap between the border and the contained Component.
259      */
getGap()260     public int getGap() {
261 
262         return gap;
263         }
264 
265     /**
266      * Sets the current color for SOLID borders and the caption text
267      * color for etched borders.
268      *
269      * @param color The new color.
270      */
setColor(Color color)271     public HolidayBorderPanel setColor(Color color) {
272 
273         this.color = color;
274         if (style == SOLID || style == IN || style == OUT)
275             repaint();
276 
277         return this;
278         }
279 
280     /**
281      * Gets the current color for SOLID borders and the caption
282      * text color for etched borders.
283      */
getColor()284     public Color getColor() {
285 
286         return color;
287         }
288 
289     /**
290      * Sets the font. Only applies to etched borders.
291      */
setTextFont(Font font)292     public HolidayBorderPanel setTextFont(Font font) {
293 
294         // set font
295         if (font != null) {
296             this.font = font;
297             if (style == IN || style == OUT) {
298                 doLayout();
299                 repaint();
300                 }
301             }
302 
303         return this;
304         }
305 
306     /**
307      * Gets the font of the text. Only applies to etched borders.
308      */
getTextFont()309     public Font getTextFont() {
310 
311         return font;
312         }
313 
314     /**
315      * Sets the text. Only applies to etched borders.
316      *
317      * @param text  The new text.
318      */
setText(String text)319     public HolidayBorderPanel setText(String text) {
320 
321         this.text = text;
322         if (style == IN || style == OUT) {
323             doLayout();
324             repaint();
325             }
326 
327         return this;
328         }
329 
330     /**
331      * Gets the text. Only applies to etched borders.
332      */
getText()333     public String getText() {
334 
335         return text;
336         }
337 
338     /**
339      * Sets the text alignment. Only applies to etched borders.
340      *
341      * @param alignment The new alignment.
342      */
setAlignment(int alignment)343     public HolidayBorderPanel setAlignment(int alignment) {
344 
345         this.alignment = alignment;
346         if (style == IN || style == OUT) {
347             doLayout();
348             repaint();
349             }
350 
351         return this;
352         }
353 
354     /**
355      * Gets the text alignment.
356      */
getAlignment()357     public int getAlignment() {
358 
359         return alignment;
360         }
361 
362     /**
363      * Repaints the border.
364      *
365      * @param g The graphics context.
366      */
paint(Graphics g)367     public void paint(Graphics g) {
368 
369         // get current dimensions
370         Dimension size = getSize();
371         int width = size.width;
372         int height = size.height;
373 
374         // set colors
375         Color light = getBackground().brighter().brighter().brighter();
376         Color dark = getBackground().darker().darker().darker();
377 
378         // Draw border
379         switch (style) {
380             case RAISED:    // 3D Border (in or out)
381             case LOWERED:
382                 Color topleft = null;
383                 Color bottomright = null;
384 
385                 // set colors
386                 if (style == RAISED) {
387                     topleft = light;
388                     bottomright = dark;
389                     }
390                 else {
391                     topleft = dark;
392                     bottomright = light;
393                     }
394 
395                 // draw border
396                 g.setColor(topleft);
397                 for (int i = 0; i < thickness; i++) {
398                     g.drawLine(i, i, width - i - 2, i);
399                     g.drawLine(i, i + 1, i, height - i - 1);
400                     }
401                 g.setColor(bottomright);
402                 for (int i = 0; i < thickness; i++) {
403                     g.drawLine(i + 1, height - i - 1, width - i - 1, height - i - 1);
404                     g.drawLine(width - i - 1, i, width - i - 1, height - i - 2);
405                     }
406                 break;
407 
408             case IN:    // Etched Border (in or out)
409             case OUT:
410                 int adjust1 = 0;
411                 int adjust2 = 0;
412 
413                 // set font and get info
414                 Font oldfont = g.getFont();
415                 g.setFont(font);
416                 FontMetrics fm = g.getFontMetrics();
417                 int ascent = fm.getAscent();
418 
419                 // set adjustment
420                 if (style == IN)
421                     adjust1 = 1;
422                 else
423                     adjust2 = 1;
424 
425                 // Calculate adjustment for text
426                 int adjustment = 0;
427                 if (text != null && text.length() > 0) {
428                     if (ascent > thickness)
429                         adjustment = (ascent - thickness) / 2;
430                     }
431 
432                 // The adjustment is there so that we always draw the
433                 // light rectangle first. Otherwise, your eye picks up
434                 // the discrepancy where the light rect. passes over
435                 // the darker rect.
436                 int x = thickness / 2;
437                 int y = thickness / 2 + adjustment;
438                 int w = width - thickness - 1;
439                 int h = height - thickness - 1 - adjustment;
440 
441                 // draw rectangles
442                 g.setColor(light);
443                 g.drawRect(x + adjust1, y + adjust1, w, h);
444                 g.setColor(dark);
445                 g.drawRect(x + adjust2, y + adjust2, w, h);
446 
447                 // draw text, if applicable
448                 if (text != null && text.length() > 0) {
449                     // calculate drawing area
450                     int fontheight = fm.getHeight();
451                     int strwidth = fm.stringWidth(text);
452 
453                     int textwidth = width - 2 * (thickness + 5);
454                     if (strwidth > textwidth)
455                         strwidth = textwidth;
456 
457                     // calculate offset for alignment
458                     int offset;
459                     switch (alignment) {
460                         case CENTER:
461                             offset = (width - strwidth) / 2;
462                             break;
463                         case RIGHT:
464                             offset = width - strwidth - thickness - 5;
465                             break;
466                         case LEFT:
467                         default: // assume left alignment if invalid
468                             offset = thickness + 5;
469                             break;
470                         }
471 
472                     // clear drawing area and set clipping region
473                     g.clearRect(offset - 5, 0, strwidth  + 10, fontheight);
474                     g.clipRect(offset, 0, strwidth, fontheight);
475 
476                     // draw text
477                     g.setColor(color);
478                     g.drawString(text, offset, ascent);
479 
480                     // restore old clipping area
481                     g.clipRect(0, 0, width, height);
482                     }
483 
484                 g.setFont(oldfont);
485                 break;
486 
487             case SOLID:
488             default: // assume SOLID
489                 g.setColor(color);
490                 for (int i = 0; i < thickness; i++)
491                     g.drawRect(i, i, width - 2 * i - 1, height - 2 * i - 1);
492             }
493 
494         }
495 
496     /**
497      * Returns the settings of this HolidayBorderPanel instance as a string.
498      */
toString()499     public String toString() {
500         StringBuffer str = new StringBuffer("HolidayBorderPanel[");
501 
502         // style
503         str.append("style=");
504         switch (style) {
505             case SOLID: str.append("SOLID"); break;
506             case RAISED: str.append("RAISED"); break;
507             case LOWERED: str.append("LOWERED"); break;
508             case IN: str.append("IN"); break;
509             case OUT: str.append("OUT"); break;
510             default: str.append("unknown");
511             }
512         str.append(",");
513 
514         // thickness
515         str.append("thickness=");
516         str.append(thickness);
517         str.append(",");
518 
519         // gap
520         str.append("gap=");
521         str.append(gap);
522         str.append(",");
523 
524         // color
525         str.append(color);
526         str.append(",");
527 
528         // font
529         str.append(font);
530         str.append(",");
531 
532         // text
533         str.append("text=");
534         str.append(text);
535         str.append(",");
536 
537         // alignment
538         str.append("alignment=");
539         switch (alignment) {
540             case LEFT: str.append("LEFT"); break;
541             case CENTER: str.append("CENTER"); break;
542             case RIGHT: str.append("RIGHT"); break;
543             default: str.append("unknown");
544             }
545 
546         str.append("]");
547 
548         return str.toString();
549         }
550 
551     }
552 
553