mdlaf.shadows.DropShadowBorder Maven / Gradle / Ivy
The newest version!
/*
* $Id: mdlaf.shadows.DropShadowBorder.java,v 1.10 2005/10/13 17:19:34 rbair Exp $
*
* Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
* Santa Clara, California 95054, U.S.A. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package mdlaf.shadows;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.util.HashMap;
import java.util.Map;
import javax.swing.UIManager;
import javax.swing.border.AbstractBorder;
import javax.swing.border.Border;
/**
* Implements a DropShadow for components. In general, the mdlaf.shadows.DropShadowBorder will work
* with any rectangular components that do not have a default border installed as part of the look
* and feel, or otherwise. For example, mdlaf.shadows.DropShadowBorder works wonderfully with
* JPanel, but horribly with JComboBox.
*
* @author rbair
*/
public class DropShadowBorder extends AbstractBorder implements Border {
private static final Map> CACHE =
new HashMap>();
private Color lineColor;
private int lineWidth;
private int shadowSize;
private float shadowOpacity;
private int cornerSize;
private boolean showTopShadow;
private boolean showLeftShadow;
private boolean showBottomShadow;
private boolean showRightShadow;
public DropShadowBorder() {
this(UIManager.getColor("Control"), 1, 5);
}
public DropShadowBorder(Color lineColor, int lineWidth, int shadowSize) {
this(lineColor, lineWidth, shadowSize, .5f, 12, false, false, true, true);
}
public DropShadowBorder(Color lineColor, int lineWidth, boolean showLeftShadow) {
this(lineColor, lineWidth, 5, .5f, 12, false, showLeftShadow, true, true);
}
public DropShadowBorder(
Color lineColor,
int lineWidth,
int shadowSize,
float shadowOpacity,
int cornerSize,
boolean showTopShadow,
boolean showLeftShadow,
boolean showBottomShadow,
boolean showRightShadow) {
this.lineColor = lineColor;
this.lineWidth = lineWidth;
this.shadowSize = shadowSize;
this.shadowOpacity = shadowOpacity;
this.cornerSize = cornerSize;
this.showTopShadow = showTopShadow;
this.showLeftShadow = showLeftShadow;
this.showBottomShadow = showBottomShadow;
this.showRightShadow = showRightShadow;
}
public void paintBorder(Component c, Graphics graphics, int x, int y, int width, int height) {
/*
* 1) Get images for this border
* 2) Paint the images for each side of the border that should be painted
*/
Map images = getImages(null);
// compute the edges of the components -- not including the border
// Insets borderInsets = getBorderInsets (c);
// int leftEdge = x + borderInsets.left - lineWidth;
// int rightEdge = x + width - borderInsets.right;
// int topEdge = y + borderInsets.top - lineWidth;
// int bottomEdge = y + height - borderInsets.bottom;
Graphics2D g2 = (Graphics2D) graphics;
g2.setColor(lineColor);
// The location and size of the shadows depends on which shadows are being
// drawn. For instance, if the left & bottom shadows are being drawn, then
// the left shadows extends all the way down to the corner, a corner is drawn,
// and then the bottom shadows begins at the corner. If, however, only the
// bottom shadows is drawn, then the bottom-left corner is drawn to the
// right of the corner, and the bottom shadows is somewhat shorter than before.
Point topLeftShadowPoint = null;
if (showLeftShadow || showTopShadow) {
topLeftShadowPoint = new Point();
if (showLeftShadow && !showTopShadow) {
topLeftShadowPoint.setLocation(x, y + shadowSize);
} else if (showLeftShadow && showTopShadow) {
topLeftShadowPoint.setLocation(x, y);
} else if (!showLeftShadow && showTopShadow) {
topLeftShadowPoint.setLocation(x + shadowSize, y);
}
}
Point bottomLeftShadowPoint = null;
if (showLeftShadow || showBottomShadow) {
bottomLeftShadowPoint = new Point();
if (showLeftShadow && !showBottomShadow) {
bottomLeftShadowPoint.setLocation(x, y + height - shadowSize - shadowSize);
} else if (showLeftShadow && showBottomShadow) {
bottomLeftShadowPoint.setLocation(x, y + height - shadowSize);
} else if (!showLeftShadow && showBottomShadow) {
bottomLeftShadowPoint.setLocation(x + shadowSize, y + height - shadowSize);
}
}
Point bottomRightShadowPoint = null;
if (showRightShadow || showBottomShadow) {
bottomRightShadowPoint = new Point();
if (showRightShadow && !showBottomShadow) {
bottomRightShadowPoint.setLocation(
x + width - shadowSize, y + height - shadowSize - shadowSize);
} else if (showRightShadow && showBottomShadow) {
bottomRightShadowPoint.setLocation(x + width - shadowSize, y + height - shadowSize);
} else if (!showRightShadow && showBottomShadow) {
bottomRightShadowPoint.setLocation(
x + width - shadowSize - shadowSize, y + height - shadowSize);
}
}
Point topRightShadowPoint = null;
if (showRightShadow || showTopShadow) {
topRightShadowPoint = new Point();
if (showRightShadow && !showTopShadow) {
topRightShadowPoint.setLocation(x + width - shadowSize, y + shadowSize);
} else if (showRightShadow && showTopShadow) {
topRightShadowPoint.setLocation(x + width - shadowSize, y);
} else if (!showRightShadow && showTopShadow) {
topRightShadowPoint.setLocation(x + width - shadowSize - shadowSize, y);
}
}
if (showLeftShadow) {
Rectangle leftShadowRect =
new Rectangle(
x,
(int) (topLeftShadowPoint.getY() + shadowSize),
shadowSize,
(int) (bottomLeftShadowPoint.getY() - topLeftShadowPoint.getY() - shadowSize));
g2.drawImage(
images
.get(Position.LEFT)
.getScaledInstance(leftShadowRect.width, leftShadowRect.height, Image.SCALE_FAST),
leftShadowRect.x,
leftShadowRect.y,
null);
}
if (showBottomShadow) {
Rectangle bottomShadowRect =
new Rectangle(
(int) (bottomLeftShadowPoint.getX() + shadowSize),
y + height - shadowSize,
(int) (bottomRightShadowPoint.getX() - bottomLeftShadowPoint.getX() - shadowSize),
shadowSize);
g2.drawImage(
images
.get(Position.BOTTOM)
.getScaledInstance(bottomShadowRect.width, bottomShadowRect.height, Image.SCALE_FAST),
bottomShadowRect.x,
bottomShadowRect.y,
null);
}
if (showRightShadow) {
Rectangle rightShadowRect =
new Rectangle(
x + width - shadowSize,
(int) (topRightShadowPoint.getY() + shadowSize),
shadowSize,
(int) (bottomRightShadowPoint.getY() - topRightShadowPoint.getY() - shadowSize));
g2.drawImage(
images
.get(Position.RIGHT)
.getScaledInstance(rightShadowRect.width, rightShadowRect.height, Image.SCALE_FAST),
rightShadowRect.x,
rightShadowRect.y,
null);
}
if (showTopShadow) {
Rectangle topShadowRect =
new Rectangle(
(int) topLeftShadowPoint.getX() + shadowSize,
y,
(int) (topRightShadowPoint.getX() - topLeftShadowPoint.getX() - shadowSize),
shadowSize);
g2.drawImage(
images
.get(Position.TOP)
.getScaledInstance(topShadowRect.width, topShadowRect.height, Image.SCALE_FAST),
topShadowRect.x,
topShadowRect.y,
null);
}
if (showLeftShadow || showTopShadow) {
g2.drawImage(
images.get(Position.TOP_LEFT),
null,
(int) topLeftShadowPoint.getX(),
(int) topLeftShadowPoint.getY());
}
if (showLeftShadow || showBottomShadow) {
g2.drawImage(
images.get(Position.BOTTOM_LEFT),
null,
(int) bottomLeftShadowPoint.getX(),
(int) bottomLeftShadowPoint.getY());
}
if (showRightShadow || showBottomShadow) {
g2.drawImage(
images.get(Position.BOTTOM_RIGHT),
null,
(int) bottomRightShadowPoint.getX(),
(int) bottomRightShadowPoint.getY());
}
if (showRightShadow || showTopShadow) {
g2.drawImage(
images.get(Position.TOP_RIGHT),
null,
(int) topRightShadowPoint.getX(),
(int) topRightShadowPoint.getY());
}
}
private Map getImages(Graphics2D g2) {
// first, check to see if an image for this size has already been rendered
// if so, use the cache. Else, draw and save
Map images = CACHE.get(shadowSize);
if (images == null) {
images = new HashMap();
/*
* Do draw a drop shadows, I have to:
* 1) Create a rounded rectangle
* 2) Create a BufferedImage to draw the rounded rect in
* 3) Translate the graphics for the image, so that the rectangle
* is centered in the drawn space. The border around the rectangle
* needs to be shadowWidth wide, so that there is space for the
* shadows to be drawn.
* 4) Draw the rounded rect as black, with an opacity of 50%
* 5) Create the BLUR_KERNEL
* 6) Blur the image
* 7) copy off the corners, sides, etc into images to be used for
* drawing the Border
*/
int rectWidth = cornerSize + 1;
RoundRectangle2D rect =
new RoundRectangle2D.Double(0, 0, rectWidth, rectWidth, cornerSize, cornerSize);
int imageWidth = rectWidth + shadowSize * 2;
BufferedImage image = new BufferedImage(imageWidth, imageWidth, BufferedImage.TYPE_INT_ARGB);
Graphics2D buffer = (Graphics2D) image.getGraphics();
buffer.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
buffer.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
buffer.setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
buffer.setRenderingHint(
RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
buffer.setColor(new Color(0.0f, 0.0f, 0.0f, shadowOpacity));
buffer.translate(shadowSize, shadowSize);
buffer.fill(rect);
float blurry =
1.0f / (float) (shadowSize * shadowSize); // 1.0f / (float)(shadowSize * shadowSize);
float[] blurKernel = new float[shadowSize * shadowSize];
for (int i = 0; i < blurKernel.length; i++) {
blurKernel[i] = blurry;
}
ConvolveOp blur = new ConvolveOp(new Kernel(shadowSize, shadowSize, blurKernel));
BufferedImage targetImage =
new BufferedImage(imageWidth, imageWidth, BufferedImage.TYPE_INT_ARGB);
((Graphics2D) targetImage.getGraphics())
.drawImage(image, blur, -(shadowSize / 2), -(shadowSize / 2));
int x = 1;
int y = 1;
int w = shadowSize;
int h = shadowSize;
images.put(Position.TOP_LEFT, targetImage.getSubimage(x, y, w, h));
x = 1;
y = h;
w = shadowSize;
h = 1;
images.put(Position.LEFT, targetImage.getSubimage(x, y, w, h));
x = 1;
y = rectWidth;
w = shadowSize;
h = shadowSize;
images.put(Position.BOTTOM_LEFT, targetImage.getSubimage(x, y, w, h));
x = cornerSize + 1;
y = rectWidth;
w = 1;
h = shadowSize;
images.put(Position.BOTTOM, targetImage.getSubimage(x, y, w, h));
x = rectWidth;
y = x;
w = shadowSize;
h = shadowSize;
images.put(Position.BOTTOM_RIGHT, targetImage.getSubimage(x, y, w, h));
x = rectWidth;
y = cornerSize + 1;
w = shadowSize;
h = 1;
images.put(Position.RIGHT, targetImage.getSubimage(x, y, w, h));
x = rectWidth;
y = 1;
w = shadowSize;
h = shadowSize;
images.put(Position.TOP_RIGHT, targetImage.getSubimage(x, y, w, h));
x = shadowSize;
y = 1;
w = 1;
h = shadowSize;
images.put(Position.TOP, targetImage.getSubimage(x, y, w, h));
buffer.dispose();
image.flush();
}
return images;
}
public Insets getBorderInsets(Component c) {
int top = 4 + (showTopShadow ? lineWidth + shadowSize : lineWidth);
int left = 4 + (showLeftShadow ? lineWidth + shadowSize : lineWidth);
int bottom = 4 + (showBottomShadow ? lineWidth + shadowSize : lineWidth);
int right = 4 + (showRightShadow ? lineWidth + shadowSize : lineWidth);
return new Insets(top, left, bottom, right);
}
public boolean isBorderOpaque() {
return true;
}
public boolean isShowTopShadow() {
return showTopShadow;
}
public boolean isShowLeftShadow() {
return showLeftShadow;
}
public boolean isShowRightShadow() {
return showRightShadow;
}
public boolean isShowBottomShadow() {
return showBottomShadow;
}
public int getLineWidth() {
return lineWidth;
}
public Color getLineColor() {
return lineColor;
}
public int getShadowSize() {
return shadowSize;
}
public float getShadowOpacity() {
return shadowOpacity;
}
public int getCornerSize() {
return cornerSize;
}
private enum Position {
TOP,
TOP_LEFT,
LEFT,
BOTTOM_LEFT,
BOTTOM,
BOTTOM_RIGHT,
RIGHT,
TOP_RIGHT
}
}