| /* | |
| * Copyright (c) 1997, 2014, 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.basic; | |
| import java.awt.Dimension; | |
| import java.awt.Graphics; | |
| import java.awt.Color; | |
| import java.awt.Graphics2D; | |
| import java.awt.geom.AffineTransform; | |
| import java.awt.geom.Path2D; | |
| import javax.swing.*; | |
| import javax.swing.plaf.UIResource; | |
| import sun.swing.SwingUtilities2; | |
| /** | |
| * JButton object that draws a scaled Arrow in one of the cardinal directions. | |
| * <p> | |
| * <strong>Warning:</strong> | |
| * Serialized objects of this class will not be compatible with | |
| * future Swing releases. The current serialization support is | |
| * appropriate for short term storage or RMI between applications running | |
| * the same version of Swing. As of 1.4, support for long term storage | |
| * of all JavaBeans | |
| * has been added to the <code>java.beans</code> package. | |
| * Please see {@link java.beans.XMLEncoder}. | |
| * | |
| * @author David Kloba | |
| */ | |
| @SuppressWarnings("serial") // Same-version serialization only | |
| public class BasicArrowButton extends JButton implements SwingConstants | |
| { | |
| /** | |
| * The direction of the arrow. One of | |
| * {@code SwingConstants.NORTH}, {@code SwingConstants.SOUTH}, | |
| * {@code SwingConstants.EAST} or {@code SwingConstants.WEST}. | |
| */ | |
| protected int direction; | |
| private Color shadow; | |
| private Color darkShadow; | |
| private Color highlight; | |
| /** | |
| * Creates a {@code BasicArrowButton} whose arrow | |
| * is drawn in the specified direction and with the specified | |
| * colors. | |
| * | |
| * @param direction the direction of the arrow; one of | |
| * {@code SwingConstants.NORTH}, {@code SwingConstants.SOUTH}, | |
| * {@code SwingConstants.EAST} or {@code SwingConstants.WEST} | |
| * @param background the background color of the button | |
| * @param shadow the color of the shadow | |
| * @param darkShadow the color of the dark shadow | |
| * @param highlight the color of the highlight | |
| * @since 1.4 | |
| */ | |
| public BasicArrowButton(int direction, Color background, Color shadow, | |
| Color darkShadow, Color highlight) { | |
| super(); | |
| setRequestFocusEnabled(false); | |
| setDirection(direction); | |
| setBackground(background); | |
| this.shadow = shadow; | |
| this.darkShadow = darkShadow; | |
| this.highlight = highlight; | |
| } | |
| /** | |
| * Creates a {@code BasicArrowButton} whose arrow | |
| * is drawn in the specified direction. | |
| * | |
| * @param direction the direction of the arrow; one of | |
| * {@code SwingConstants.NORTH}, {@code SwingConstants.SOUTH}, | |
| * {@code SwingConstants.EAST} or {@code SwingConstants.WEST} | |
| */ | |
| public BasicArrowButton(int direction) { | |
| this(direction, UIManager.getColor("control"), UIManager.getColor("controlShadow"), | |
| UIManager.getColor("controlDkShadow"), UIManager.getColor("controlLtHighlight")); | |
| } | |
| /** | |
| * Returns the direction of the arrow. | |
| * | |
| * @return the direction of the arrow | |
| */ | |
| public int getDirection() { | |
| return direction; | |
| } | |
| /** | |
| * Sets the direction of the arrow. | |
| * | |
| * @param direction the direction of the arrow; one of | |
| * of {@code SwingConstants.NORTH}, | |
| * {@code SwingConstants.SOUTH}, | |
| * {@code SwingConstants.EAST} or {@code SwingConstants.WEST} | |
| */ | |
| public void setDirection(int direction) { | |
| this.direction = direction; | |
| } | |
| public void paint(Graphics g) { | |
| Color origColor; | |
| boolean isPressed, isEnabled; | |
| int w, h, size; | |
| w = getSize().width; | |
| h = getSize().height; | |
| origColor = g.getColor(); | |
| isPressed = getModel().isPressed(); | |
| isEnabled = isEnabled(); | |
| g.setColor(getBackground()); | |
| g.fillRect(1, 1, w-2, h-2); | |
| /// Draw the proper Border | |
| if (getBorder() != null && !(getBorder() instanceof UIResource)) { | |
| paintBorder(g); | |
| } else if (isPressed) { | |
| g.setColor(shadow); | |
| g.drawRect(0, 0, w-1, h-1); | |
| } else { | |
| // Using the background color set above | |
| g.drawLine(0, 0, 0, h-1); | |
| g.drawLine(1, 0, w-2, 0); | |
| g.setColor(highlight); // inner 3D border | |
| g.drawLine(1, 1, 1, h-3); | |
| g.drawLine(2, 1, w-3, 1); | |
| g.setColor(shadow); // inner 3D border | |
| g.drawLine(1, h-2, w-2, h-2); | |
| g.drawLine(w-2, 1, w-2, h-3); | |
| g.setColor(darkShadow); // black drop shadow __| | |
| g.drawLine(0, h-1, w-1, h-1); | |
| g.drawLine(w-1, h-1, w-1, 0); | |
| } | |
| // If there's no room to draw arrow, bail | |
| if(h < 5 || w < 5) { | |
| g.setColor(origColor); | |
| return; | |
| } | |
| if (isPressed) { | |
| g.translate(1, 1); | |
| } | |
| // Draw the arrow | |
| size = Math.min((h - 4) / 3, (w - 4) / 3); | |
| size = Math.max(size, 2); | |
| paintTriangle(g, (w - size) / 2, (h - size) / 2, | |
| size, direction, isEnabled); | |
| // Reset the Graphics back to it's original settings | |
| if (isPressed) { | |
| g.translate(-1, -1); | |
| } | |
| g.setColor(origColor); | |
| } | |
| /** | |
| * Returns the preferred size of the {@code BasicArrowButton}. | |
| * | |
| * @return the preferred size | |
| */ | |
| public Dimension getPreferredSize() { | |
| return new Dimension(16, 16); | |
| } | |
| /** | |
| * Returns the minimum size of the {@code BasicArrowButton}. | |
| * | |
| * @return the minimum size | |
| */ | |
| public Dimension getMinimumSize() { | |
| return new Dimension(5, 5); | |
| } | |
| /** | |
| * Returns the maximum size of the {@code BasicArrowButton}. | |
| * | |
| * @return the maximum size | |
| */ | |
| public Dimension getMaximumSize() { | |
| return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); | |
| } | |
| /** | |
| * Returns whether the arrow button should get the focus. | |
| * {@code BasicArrowButton}s are used as a child component of | |
| * composite components such as {@code JScrollBar} and | |
| * {@code JComboBox}. Since the composite component typically gets the | |
| * focus, this method is overridden to return {@code false}. | |
| * | |
| * @return {@code false} | |
| */ | |
| @SuppressWarnings("deprecation") | |
| public boolean isFocusTraversable() { | |
| return false; | |
| } | |
| /** | |
| * Paints a triangle. | |
| * | |
| * @param g the {@code Graphics} to draw to | |
| * @param x the x coordinate | |
| * @param y the y coordinate | |
| * @param size the size of the triangle to draw | |
| * @param direction the direction in which to draw the arrow; | |
| * one of {@code SwingConstants.NORTH}, | |
| * {@code SwingConstants.SOUTH}, {@code SwingConstants.EAST} or | |
| * {@code SwingConstants.WEST} | |
| * @param isEnabled whether or not the arrow is drawn enabled | |
| */ | |
| public void paintTriangle(Graphics g, int x, int y, int size, | |
| int direction, boolean isEnabled) { | |
| if (SwingUtilities2.isScaledGraphics(g)) { | |
| paintScaledTriangle(g, x, y, size, direction, isEnabled); | |
| } else { | |
| paintUnscaledTriangle(g, x, y, size, direction, isEnabled); | |
| } | |
| } | |
| private void paintUnscaledTriangle(Graphics g, int x, int y, int size, | |
| int direction, boolean isEnabled) | |
| { | |
| Color oldColor = g.getColor(); | |
| int mid, i, j; | |
| j = 0; | |
| size = Math.max(size, 2); | |
| mid = (size / 2) - 1; | |
| g.translate(x, y); | |
| if(isEnabled) | |
| g.setColor(darkShadow); | |
| else | |
| g.setColor(shadow); | |
| switch(direction) { | |
| case NORTH: | |
| for(i = 0; i < size; i++) { | |
| g.drawLine(mid-i, i, mid+i, i); | |
| } | |
| if(!isEnabled) { | |
| g.setColor(highlight); | |
| g.drawLine(mid-i+2, i, mid+i, i); | |
| } | |
| break; | |
| case SOUTH: | |
| if(!isEnabled) { | |
| g.translate(1, 1); | |
| g.setColor(highlight); | |
| for(i = size-1; i >= 0; i--) { | |
| g.drawLine(mid-i, j, mid+i, j); | |
| j++; | |
| } | |
| g.translate(-1, -1); | |
| g.setColor(shadow); | |
| } | |
| j = 0; | |
| for(i = size-1; i >= 0; i--) { | |
| g.drawLine(mid-i, j, mid+i, j); | |
| j++; | |
| } | |
| break; | |
| case WEST: | |
| for(i = 0; i < size; i++) { | |
| g.drawLine(i, mid-i, i, mid+i); | |
| } | |
| if(!isEnabled) { | |
| g.setColor(highlight); | |
| g.drawLine(i, mid-i+2, i, mid+i); | |
| } | |
| break; | |
| case EAST: | |
| if(!isEnabled) { | |
| g.translate(1, 1); | |
| g.setColor(highlight); | |
| for(i = size-1; i >= 0; i--) { | |
| g.drawLine(j, mid-i, j, mid+i); | |
| j++; | |
| } | |
| g.translate(-1, -1); | |
| g.setColor(shadow); | |
| } | |
| j = 0; | |
| for(i = size-1; i >= 0; i--) { | |
| g.drawLine(j, mid-i, j, mid+i); | |
| j++; | |
| } | |
| break; | |
| } | |
| g.translate(-x, -y); | |
| g.setColor(oldColor); | |
| } | |
| private void paintScaledTriangle(Graphics g, double x, double y, double size, | |
| int direction, boolean isEnabled) { | |
| size = Math.max(size, 2); | |
| Path2D.Double path = new Path2D.Double(); | |
| path.moveTo(-size, size / 2); | |
| path.lineTo(size, size / 2); | |
| path.lineTo(0, -size / 2); | |
| path.closePath(); | |
| AffineTransform affineTransform = new AffineTransform(); | |
| affineTransform.rotate(Math.PI * (direction - 1) / 4); | |
| path.transform(affineTransform); | |
| Graphics2D g2d = (Graphics2D) g; | |
| double tx = x + size / 2; | |
| double ty = y + size / 2; | |
| g2d.translate(tx, ty); | |
| Color oldColor = g.getColor(); | |
| if (!isEnabled) { | |
| g2d.translate(1, 0); | |
| g2d.setColor(highlight); | |
| g2d.fill(path); | |
| g2d.translate(-1, 0); | |
| } | |
| g2d.setColor(isEnabled ? darkShadow : shadow); | |
| g2d.fill(path); | |
| g2d.translate(-tx, -ty); | |
| g2d.setColor(oldColor); | |
| } | |
| } |