/*
* @(#)PlafPaintUtils.java
*
* $Date: 2012-08-09 01:47:06 -0500 (Thu, 09 Aug 2012) $
*
* Copyright (c) 2011 by Jeremy Wood.
* All rights reserved.
*
* The copyright of this software is owned by Jeremy Wood.
* You may not use, copy or modify this software, except in
* accordance with the license agreement you entered into with
* Jeremy Wood. For details see accompanying license terms.
*
* This software is probably, but not necessarily, discussed here:
* http://javagraphics.java.net/
*
* That site should also contain the most recent official version
* of this software. (See the SVN repository for more details.)
*/
package ale.util.colors.bric.plaf;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.TexturePaint;
import java.awt.image.BufferedImage;
import java.util.Hashtable;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import ale.util.colors.bric.util.JVM;
/**
* Some static methods for some common painting functions.
*
* @author Jeremy Wood
**/
public class PlafPaintUtils {
/** Four shades of white, each with increasing opacity. */
final static Color[] whites = new Color[] {
new Color(255, 255, 255, 50),
new Color(255, 255, 255, 100),
new Color(255, 255, 255, 150)
};
/** Four shades of black, each with increasing opacity. */
final static Color[] blacks = new Color[] {
new Color(0, 0, 0, 50),
new Color(0, 0, 0, 100),
new Color(0, 0, 0, 150)
};
/**
* @return the color used to indicate when a component has focus. By default this uses the color (64,113,167), but
* you can override this by calling: <BR>
* <code>UIManager.put("focusRing",customColor);</code>
*/
public static Color getFocusRingColor() {
Object obj = UIManager.getColor("Focus.color");
if (obj instanceof Color) {
return (Color) obj;
}
obj = UIManager.getColor("focusRing");
if (obj instanceof Color) {
return (Color) obj;
}
return new Color(64, 113, 167);
}
/**
* Paints 3 different strokes around a shape to indicate focus. The widest stroke is the most transparent, so this
* achieves a nice "glow" effect.
* <P>
* The catch is that you have to render this underneath the shape, and the shape should be filled completely.
*
* @param g
* the graphics to paint to
* @param shape
* the shape to outline
* @param pixelSize
* the number of pixels the outline should cover.
*/
public static void paintFocus(Graphics2D g, Shape shape, int pixelSize) {
Color focusColor = getFocusRingColor();
Color[] focusArray = new Color[] {
new Color(focusColor.getRed(), focusColor.getGreen(), focusColor.getBlue(), 235),
new Color(focusColor.getRed(), focusColor.getGreen(), focusColor.getBlue(), 130),
new Color(focusColor.getRed(), focusColor.getGreen(), focusColor.getBlue(), 80)
};
if (JVM.usingQuartz) {
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
} else {
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
}
g.setStroke(new BasicStroke((2 * pixelSize) + 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g.setColor(focusArray[2]);
g.draw(shape);
if (((2 * pixelSize) + 1) > 0) {
g.setStroke(new BasicStroke(((2 * pixelSize) - 2) + 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g.setColor(focusArray[1]);
g.draw(shape);
}
if ((((2 * pixelSize) - 4) + 1) > 0) {
g.setStroke(new BasicStroke(((2 * pixelSize) - 4) + 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g.setColor(focusArray[0]);
g.draw(shape);
}
}
/**
* Uses translucent shades of white and black to draw highlights and shadows around a rectangle, and then frames the
* rectangle with a shade of gray (120).
* <P>
* This should be called to add a finishing touch on top of existing graphics.
*
* @param g
* the graphics to paint to.
* @param r
* the rectangle to paint.
*/
public static void drawBevel(Graphics2D g, Rectangle r) {
g.setStroke(new BasicStroke(1));
drawColors(blacks, g, r.x, r.y + r.height, r.x + r.width, r.y + r.height, SwingConstants.SOUTH);
drawColors(blacks, g, r.x + r.width, r.y, r.x + r.width, r.y + r.height, SwingConstants.EAST);
drawColors(whites, g, r.x, r.y, r.x + r.width, r.y, SwingConstants.NORTH);
drawColors(whites, g, r.x, r.y, r.x, r.y + r.height, SwingConstants.WEST);
g.setColor(new Color(120, 120, 120));
g.drawRect(r.x, r.y, r.width, r.height);
}
private static void drawColors(Color[] colors, Graphics g, int x1, int y1, int x2, int y2, int direction) {
for (int a = 0; a < colors.length; a++) {
g.setColor(colors[colors.length - a - 1]);
if (direction == SwingConstants.SOUTH) {
g.drawLine(x1, y1 - a, x2, y2 - a);
} else if (direction == SwingConstants.NORTH) {
g.drawLine(x1, y1 + a, x2, y2 + a);
} else if (direction == SwingConstants.EAST) {
g.drawLine(x1 - a, y1, x2 - a, y2);
} else if (direction == SwingConstants.WEST) {
g.drawLine(x1 + a, y1, x2 + a, y2);
}
}
}
/** The table used to store vertical gradients. */
private static Hashtable<String, TexturePaint> verticalGradients;
/**
* Create a vertical gradient. This gradient is stored in a table and reused throughout the rest of this session.
*
* @param name
* an identifying key for this gradient (used to cache it).
* @param height
* the height of the gradient
* @param y
* the y offset of the gradient
* @param positions
* the fractional positions of each color (between [0,1]).
* @param colors
* one color for each position.
* @return the vertical gradient.
*/
synchronized static Paint getVerticalGradient(String name,
int height, int y,
float[] positions,
Color[] colors) {
if (verticalGradients == null) {
verticalGradients = new Hashtable<String, TexturePaint>();
}
String key = name + " " + height + " " + y;
TexturePaint paint = verticalGradients.get(key);
if (paint == null) {
height = Math.max(height, 1); // before a component is laid out, it may be 0x0
BufferedImage bi = new BufferedImage(1, height, BufferedImage.TYPE_INT_ARGB);
int[] array = new int[height];
for (int a = 0; a < array.length; a++) {
float f = a;
f = f / ((array.length - 1));
boolean hit = false;
findMatch:
for (int b = 1; b < positions.length; b++) {
if ((f >= positions[b - 1]) && (f < positions[b])) {
float p = (f - positions[b - 1]) / (positions[b] - positions[b - 1]);
array[a] = tween(colors[b - 1], colors[b], p).getRGB();
hit = true;
break findMatch;
}
}
if (!hit) {
array[a] = colors[colors.length - 1].getRGB();
}
}
bi.getRaster().setDataElements(0, 0, 1, height, array);
paint = new TexturePaint(bi, new Rectangle(0, y, 1, height));
verticalGradients.put(key, paint);
}
return paint;
}
/** Tweens between the two arguments. */
private static Color tween(Color c1, Color c2, float p) {
int r1 = c1.getRed();
int g1 = c1.getGreen();
int b1 = c1.getBlue();
int a1 = c1.getAlpha();
int r2 = c2.getRed();
int g2 = c2.getGreen();
int b2 = c2.getBlue();
int a2 = c2.getAlpha();
return new Color((int) ((r1 * (1 - p)) + (r2 * p)),
(int) ((g1 * (1 - p)) + (g2 * p)),
(int) ((b1 * (1 - p)) + (b2 * p)),
(int) ((a1 * (1 - p)) + (a2 * p)));
}
private static Hashtable<String, TexturePaint> checkers;
public static TexturePaint getCheckerBoard(int checkerSize) {
return getCheckerBoard(checkerSize, Color.white, Color.lightGray);
}
public static TexturePaint getCheckerBoard(int checkerSize, Color color1, Color color2) {
String key = checkerSize + " " + color1.toString() + " " + color2.toString();
if (checkers == null) {
checkers = new Hashtable<String, TexturePaint>();
}
TexturePaint paint = checkers.get(key);
if (paint == null) {
BufferedImage bi = new BufferedImage(2 * checkerSize, 2 * checkerSize, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bi.createGraphics();
g.setColor(color1);
g.fillRect(0, 0, 2 * checkerSize, 2 * checkerSize);
g.setColor(color2);
g.fillRect(0, 0, checkerSize, checkerSize);
g.fillRect(checkerSize, checkerSize, checkerSize, checkerSize);
g.dispose();
paint = new TexturePaint(bi, new Rectangle(0, 0, bi.getWidth(), bi.getHeight()));
checkers.put(key, paint);
}
return paint;
}
}