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