package com.limegroup.gnutella.gui.border; import java.awt.Color; import java.awt.Component; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.Toolkit; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.border.TitledBorder; /** * An TitledBorder that also draws an icon. * * THIS CLASS IS ONLY TESTED TO LOOK DECENT WITH * A LEFT-TO-RIGHT LAYOUT AND THE TITLE ON THE TOP. */ public class TitledIconBorder extends TitledBorder { protected Icon icon; private Point textLoc = new Point(); private Point iconLoc = new Point(); /** * Space between the edge of the component & the border. */ private static final int BORDER_SPACING = 2; /** * Space between icon & text. */ private static final int ICON_SPACING = 4; // Horizontal inset of title that is left or right justified static protected final int TITLE_INSET_H = 8; /** * Space between the border & icon and the text & border. */ private static final int EMPTY_SPACE = 4; public TitledIconBorder() { super(UIManager.getBorder("TitledBorder.border")); } public TitledIconBorder(Border border) { super(border); } public void setIcon(Icon icon) { this.icon = icon; } public Icon getIcon() { return icon; } /** * Paints the border for the specified component with the * specified position and size. * @param c the component for which this border is being painted * @param g the paint graphics * @param x the x position of the painted border * @param y the y position of the painted border * @param width the width of the painted border * @param height the height of the painted border */ public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { if(icon == null) { super.paintBorder(c, g, x, y, width, height); return; } Border border = getBorder(); final String title = getTitle(); final int titlePos = getTitlePosition() == DEFAULT_POSITION ? TOP : getTitlePosition(); if (title == null || title.equals("")) { if (border != null) { border.paintBorder(c, g, x, y, width, height); } return; } Rectangle grooveRect = new Rectangle(x + EDGE_SPACING, y + EDGE_SPACING, width - (EDGE_SPACING * 2), height - (EDGE_SPACING * 2)); Font font = g.getFont(); Color color = g.getColor(); g.setFont(getFont(c)); JComponent jc = (c instanceof JComponent) ? (JComponent)c : null; FontMetrics fm = jc == null ? Toolkit.getDefaultToolkit().getFontMetrics(font) : jc.getFontMetrics(font); int titleHeight = Math.max(icon.getIconHeight(), fm.getHeight()); int descent = fm.getDescent(); int ascent = fm.getAscent(); int diff; int titleWidth = fm.stringWidth(title) + ICON_SPACING + icon.getIconWidth(); Insets insets; if (border != null) { insets = border.getBorderInsets(c); } else { insets = new Insets(0, 0, 0, 0); } switch (titlePos) { case ABOVE_TOP: diff = ascent + descent + (Math.max(EDGE_SPACING, BORDER_SPACING*2) - EDGE_SPACING); grooveRect.y += diff; grooveRect.height -= diff; textLoc.y = grooveRect.y - (descent + BORDER_SPACING); iconLoc.y = grooveRect.y + BORDER_SPACING; break; case TOP: diff = Math.max(0, ((ascent/2) + BORDER_SPACING) - EDGE_SPACING); grooveRect.y += diff; grooveRect.height -= diff; textLoc.y = (grooveRect.y - descent) + (insets.top + ascent + descent)/2; iconLoc.y = grooveRect.y - (insets.top / 2); break; case BELOW_TOP: textLoc.y = grooveRect.y + insets.top + ascent + BORDER_SPACING; iconLoc.y = grooveRect.y - insets.top - BORDER_SPACING; break; case ABOVE_BOTTOM: textLoc.y = (grooveRect.y + grooveRect.height) - (insets.bottom + descent + BORDER_SPACING); iconLoc.y = grooveRect.y + grooveRect.height + insets.bottom + BORDER_SPACING; break; case BOTTOM: grooveRect.height -= titleHeight/2; textLoc.y = ((grooveRect.y + grooveRect.height) - descent) + ((ascent + descent) - insets.bottom)/2; iconLoc.y = grooveRect.y + grooveRect.height + (insets.bottom/2); break; case BELOW_BOTTOM: grooveRect.height -= titleHeight; textLoc.y = grooveRect.y + grooveRect.height + ascent + BORDER_SPACING; iconLoc.y = grooveRect.y + grooveRect.height - BORDER_SPACING; break; } /* // not java 1.1.8 compatable. :( int justification = getTitleJustification(); if(c.getComponentOrientation().isLeftToRight()) { if(justification==LEADING || justification==DEFAULT_JUSTIFICATION) { justification = LEFT; } else if(justification==TRAILING) { justification = RIGHT; } } else { if(justification==LEADING || justification==DEFAULT_JUSTIFICATION) { justification = RIGHT; } else if(justification==TRAILING) { justification = LEFT; } } */ int justification = LEFT; switch (justification) { case LEFT: iconLoc.x = grooveRect.x + TITLE_INSET_H + insets.left; textLoc.x = iconLoc.x + icon.getIconWidth() + ICON_SPACING; break; case RIGHT: iconLoc.x = grooveRect.x + grooveRect.width - (titleWidth + TITLE_INSET_H + insets.right); textLoc.x = iconLoc.x - icon.getIconWidth() - ICON_SPACING; break; case CENTER: iconLoc.x = grooveRect.x + ((grooveRect.width - titleWidth) / 2); textLoc.x = iconLoc.x + icon.getIconWidth() + ICON_SPACING; break; } // If title is positioned in middle of border AND its fontsize // is greater than the border's thickness, we'll need to paint // the border in sections to leave space for the component's background // to show through the title. // if (border != null) { if (((titlePos == TOP) && (grooveRect.y > textLoc.y - ascent)) || (titlePos == BOTTOM && (grooveRect.y + grooveRect.height < textLoc.y + descent))) { Rectangle clipRect = new Rectangle(); // save original clip Rectangle saveClip = g.getClipBounds(); // paint strip left of text clipRect.setBounds(saveClip); if (computeIntersection(clipRect, x, y, iconLoc.x-EMPTY_SPACE-x, height)) { g.setClip(clipRect); border.paintBorder(c, g, grooveRect.x, grooveRect.y, grooveRect.width, grooveRect.height); } // paint strip right of text clipRect.setBounds(saveClip); if (computeIntersection(clipRect, iconLoc.x+titleWidth+EMPTY_SPACE+2, y, x+width-(iconLoc.x+titleWidth+EMPTY_SPACE+2), height)) { g.setClip(clipRect); border.paintBorder(c, g, grooveRect.x, grooveRect.y, grooveRect.width, grooveRect.height); } if (titlePos == TOP) { // paint strip below text clipRect.setBounds(saveClip); if (computeIntersection(clipRect, iconLoc.x-EMPTY_SPACE, textLoc.y+descent, titleWidth+(EMPTY_SPACE*2)+2, y+height-textLoc.y-descent)) { g.setClip(clipRect); border.paintBorder(c, g, grooveRect.x, grooveRect.y, grooveRect.width, grooveRect.height); } } else { // titlePos == BOTTOM // paint strip above text clipRect.setBounds(saveClip); if (computeIntersection(clipRect, iconLoc.x-EMPTY_SPACE, y, titleWidth+(EMPTY_SPACE*2)+2, textLoc.y - ascent - y)) { g.setClip(clipRect); border.paintBorder(c, g, grooveRect.x, grooveRect.y, grooveRect.width, grooveRect.height); } } // restore clip g.setClip(saveClip); } else { border.paintBorder(c, g, grooveRect.x, grooveRect.y, grooveRect.width, grooveRect.height); } } g.setColor(getTitleColor()); if(title.length() > 0) g.drawString(getTitle(), textLoc.x, textLoc.y); icon.paintIcon(c, g, iconLoc.x, iconLoc.y-5); g.setFont(font); g.setColor(color); } private static boolean computeIntersection(Rectangle dest, int rx, int ry, int rw, int rh) { int x1 = Math.max(rx, dest.x); int x2 = Math.min(rx + rw, dest.x + dest.width); int y1 = Math.max(ry, dest.y); int y2 = Math.min(ry + rh, dest.y + dest.height); dest.x = x1; dest.y = y1; dest.width = x2 - x1; dest.height = y2 - y1; return !(dest.width <= 0 || dest.height <= 0); } }