| /* |
| * 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)); |
| } |
| } |
| |