/* |
|
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. |
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
* |
|
* This code is free software; you can redistribute it and/or modify it |
|
* under the terms of the GNU General Public License version 2 only, as |
|
* published by the Free Software Foundation. Oracle designates this |
|
* particular file as subject to the "Classpath" exception as provided |
|
* by Oracle in the LICENSE file that accompanied this code. |
|
* |
|
* This code 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 General Public License |
|
* version 2 for more details (a copy is included in the LICENSE file that |
|
* accompanied this code). |
|
* |
|
* You should have received a copy of the GNU General Public License version |
|
* 2 along with this work; if not, write to the Free Software Foundation, |
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
* |
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
* or visit www.oracle.com if you need additional information or have any |
|
* questions. |
|
*/ |
|
package javax.swing.plaf.nimbus; |
|
import javax.swing.border.Border; |
|
import javax.swing.JComponent; |
|
import java.awt.Insets; |
|
import java.awt.Component; |
|
import java.awt.Graphics; |
|
import java.awt.Graphics2D; |
|
import java.awt.Color; |
|
import java.awt.RenderingHints; |
|
import java.awt.Dimension; |
|
import java.awt.image.BufferedImage; |
|
/** |
|
* LoweredBorder - A recessed rounded inner shadowed border. Used as the |
|
* standard Nimbus TitledBorder. This class is both a painter and a swing |
|
* border. |
|
* |
|
* @author Jasper Potts |
|
*/ |
|
class LoweredBorder extends AbstractRegionPainter implements Border { |
|
private static final int IMG_SIZE = 30; |
|
private static final int RADIUS = 13; |
|
private static final Insets INSETS = new Insets(10,10,10,10); |
|
private static final PaintContext PAINT_CONTEXT = new PaintContext(INSETS, |
|
new Dimension(IMG_SIZE,IMG_SIZE),false, |
|
PaintContext.CacheMode.NINE_SQUARE_SCALE, |
|
Integer.MAX_VALUE, Integer.MAX_VALUE); |
|
// ========================================================================= |
|
// Painter Methods |
|
@Override |
|
protected Object[] getExtendedCacheKeys(JComponent c) { |
|
return (c != null) |
|
? new Object[] { c.getBackground() } |
|
: null; |
|
} |
|
/** |
|
* Actually performs the painting operation. Subclasses must implement this |
|
* method. The graphics object passed may represent the actual surface being |
|
* rendered to, or it may be an intermediate buffer. It has also been |
|
* pre-translated. Simply render the component as if it were located at 0, 0 |
|
* and had a width of <code>width</code> and a height of |
|
* <code>height</code>. For performance reasons, you may want to read the |
|
* clip from the Graphics2D object and only render within that space. |
|
* |
|
* @param g The Graphics2D surface to paint to |
|
* @param c The JComponent related to the drawing event. For example, |
|
* if the region being rendered is Button, then <code>c</code> |
|
* will be a JButton. If the region being drawn is |
|
* ScrollBarSlider, then the component will be JScrollBar. |
|
* This value may be null. |
|
* @param width The width of the region to paint. Note that in the case of |
|
* painting the foreground, this value may differ from |
|
* c.getWidth(). |
|
* @param height The height of the region to paint. Note that in the case of |
|
* painting the foreground, this value may differ from |
|
* c.getHeight(). |
|
*/ |
|
protected void doPaint(Graphics2D g, JComponent c, int width, int height, |
|
Object[] extendedCacheKeys) { |
|
Color color = (c == null) ? Color.BLACK : c.getBackground(); |
|
BufferedImage img1 = new BufferedImage(IMG_SIZE,IMG_SIZE, |
|
BufferedImage.TYPE_INT_ARGB); |
|
BufferedImage img2 = new BufferedImage(IMG_SIZE,IMG_SIZE, |
|
BufferedImage.TYPE_INT_ARGB); |
|
// draw shadow shape |
|
Graphics2D g2 = (Graphics2D)img1.getGraphics(); |
|
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, |
|
RenderingHints.VALUE_ANTIALIAS_ON); |
|
g2.setColor(color); |
|
g2.fillRoundRect(2,0,26,26,RADIUS,RADIUS); |
|
g2.dispose(); |
|
// draw shadow |
|
InnerShadowEffect effect = new InnerShadowEffect(); |
|
effect.setDistance(1); |
|
effect.setSize(3); |
|
effect.setColor(getLighter(color, 2.1f)); |
|
effect.setAngle(90); |
|
effect.applyEffect(img1,img2,IMG_SIZE,IMG_SIZE); |
|
// draw outline to img2 |
|
g2 = (Graphics2D)img2.getGraphics(); |
|
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, |
|
RenderingHints.VALUE_ANTIALIAS_ON); |
|
g2.setClip(0,28,IMG_SIZE,1); |
|
g2.setColor(getLighter(color, 0.90f)); |
|
g2.drawRoundRect(2,1,25,25,RADIUS,RADIUS); |
|
g2.dispose(); |
|
// draw final image |
|
if (width != IMG_SIZE || height != IMG_SIZE){ |
|
ImageScalingHelper.paint(g,0,0,width,height,img2, INSETS, INSETS, |
|
ImageScalingHelper.PaintType.PAINT9_STRETCH, |
|
ImageScalingHelper.PAINT_ALL); |
|
} else { |
|
g.drawImage(img2,0,0,c); |
|
} |
|
img1 = null; |
|
img2 = null; |
|
} |
|
/** |
|
* <p>Gets the PaintContext for this painting operation. This method is |
|
* called on every paint, and so should be fast and produce no garbage. The |
|
* PaintContext contains information such as cache hints. It also contains |
|
* data necessary for decoding points at runtime, such as the stretching |
|
* insets, the canvas size at which the encoded points were defined, and |
|
* whether the stretching insets are inverted.</p> |
|
* <p/> |
|
* <p> This method allows for subclasses to package the painting of |
|
* different states with possibly different canvas sizes, etc, into one |
|
* AbstractRegionPainter implementation.</p> |
|
* |
|
* @return a PaintContext associated with this paint operation. |
|
*/ |
|
protected PaintContext getPaintContext() { |
|
return PAINT_CONTEXT; |
|
} |
|
// ========================================================================= |
|
// Border Methods |
|
/** |
|
* Returns the insets of the border. |
|
* |
|
* @param c the component for which this border insets value applies |
|
*/ |
|
public Insets getBorderInsets(Component c) { |
|
return (Insets) INSETS.clone(); |
|
} |
|
/** |
|
* Returns whether or not the border is opaque. If the border is opaque, it |
|
* is responsible for filling in it's own background when painting. |
|
*/ |
|
public boolean isBorderOpaque() { |
|
return false; |
|
} |
|
/** |
|
* 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) { |
|
JComponent comp = (c instanceof JComponent)?(JComponent)c:null; |
|
if (g instanceof Graphics2D){ |
|
Graphics2D g2 = (Graphics2D)g; |
|
g2.translate(x,y); |
|
paint(g2,comp, width, height); |
|
g2.translate(-x,-y); |
|
} else { |
|
BufferedImage img = new BufferedImage(IMG_SIZE,IMG_SIZE, |
|
BufferedImage.TYPE_INT_ARGB); |
|
Graphics2D g2 = (Graphics2D)img.getGraphics(); |
|
paint(g2,comp, width, height); |
|
g2.dispose(); |
|
ImageScalingHelper.paint(g,x,y,width,height,img,INSETS, INSETS, |
|
ImageScalingHelper.PaintType.PAINT9_STRETCH, |
|
ImageScalingHelper.PAINT_ALL); |
|
} |
|
} |
|
private Color getLighter(Color c, float factor){ |
|
return new Color(Math.min((int)(c.getRed()/factor), 255), |
|
Math.min((int)(c.getGreen()/factor), 255), |
|
Math.min((int)(c.getBlue()/factor), 255)); |
|
} |
|
} |
|