/** * */ package javax.swing.origamist; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Stroke; import java.awt.geom.RoundRectangle2D; import java.util.Hashtable; import javax.swing.border.AbstractBorder; import javax.swing.border.Border; /** * A high-quality antialiased rounded border. * * @author Keilly, http://blog.keilly.com/2008/05/creating-swing-widget-part-2-border.html */ public class RoundedBorder extends AbstractBorder { /** */ private static final long serialVersionUID = 1473481894085410085L; /** The insets of the border. */ protected Insets insets; /** The stroke to draw the line with. */ protected Stroke stroke = null; /** Color of the drawn line. */ protected Color strokeColor = Color.BLACK; /** The size of the arc to use. */ protected int arc; /** The width of the stroke to use. */ protected float strokeWidth = 0f; // TODO maybe make this static and add <code>strokeWidth</code> to the search key /** The cached rectangles containing the content based on the requested size. */ protected Hashtable<Dimension, RoundRectangle2D.Float> rect = new Hashtable<Dimension, RoundRectangle2D.Float>(); /** * Simple rounded border with no outline. * * @param arc The size of the arc to use. */ public RoundedBorder(int arc) { this.arc = arc; int i = (int) (arc / Math.PI) / 2; insets = new Insets(i, i, i, i); } /** * Rounded border with an outline. * * @param arc The size of the arc to use. * @param strokeWidth Width of the outline. * @param color Color of the outline. */ public RoundedBorder(int arc, float strokeWidth, Color color) { this.arc = arc; int i = (int) ((arc / Math.PI) + ((strokeWidth * 2) / (Math.PI))); insets = new Insets(i, i, i, i); this.stroke = new BasicStroke(strokeWidth); this.strokeColor = color; this.strokeWidth = strokeWidth; } /** * Returns the round rectangle that is used to draw the inner area of the component. * * @param dim The outer dimension of the component. * @return The round rectangle that is used to draw the inner area of the component. */ public RoundRectangle2D getRoundRectangle(Dimension dim) { if (rect.get(dim) == null) { int i = (int) strokeWidth / 2; rect.put(dim, new RoundRectangle2D.Float(i, i, dim.width - strokeWidth, dim.height - strokeWidth, arc, arc)); } return rect.get(dim); } @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { Graphics2D g2 = (Graphics2D) g.create(); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Dimension dim = new Dimension(width, height); if (stroke != null) { int i = (int) strokeWidth / 2; if (rect.get(dim) == null) rect.put(dim, new RoundRectangle2D.Float(i, i, width - strokeWidth, height - strokeWidth, arc, arc)); g2.translate(x, y); g2.setColor(c.getBackground()); g2.fill(rect.get(dim)); g2.setColor(strokeColor); g2.setStroke(stroke); g2.draw(rect.get(dim)); } else { if (rect.get(dim) == null) rect.put(dim, new RoundRectangle2D.Float(0, 0, width, height, arc, arc)); g2.translate(x, y); g2.setColor(c.getBackground()); g2.fill(rect.get(dim)); } } @Override public Insets getBorderInsets(Component c) { return insets; } @Override public Insets getBorderInsets(Component c, Insets insets) { return insets; } @Override public Rectangle getInteriorRectangle(Component c, int x, int y, int width, int height) { return getInteriorRectangle(c, this, x, y, width, height); } public static Rectangle getInteriorRectangle(Component c, Border b, int x, int y, int width, int height) { Insets insets; if (b != null) insets = b.getBorderInsets(c); else insets = new Insets(0, 0, 0, 0); return new Rectangle(x + insets.left, y + insets.top, width - insets.right - insets.left, height - insets.top - insets.bottom); } }