1 /* 2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package javax.swing.plaf.basic; 26 27 import java.awt.Dimension; 28 import java.awt.Graphics; 29 import java.awt.Color; 30 31 import javax.swing.*; 32 import javax.swing.plaf.UIResource; 33 34 /** 35 * JButton object that draws a scaled Arrow in one of the cardinal directions. 36 * <p> 37 * <strong>Warning:</strong> 38 * Serialized objects of this class will not be compatible with 39 * future Swing releases. The current serialization support is 40 * appropriate for short term storage or RMI between applications running 41 * the same version of Swing. As of 1.4, support for long term storage 42 * of all JavaBeans™ 43 * has been added to the <code>java.beans</code> package. 44 * Please see {@link java.beans.XMLEncoder}. 45 * 46 * @author David Kloba 47 */ 48 @SuppressWarnings("serial") // Same-version serialization only 49 public class BasicArrowButton extends JButton implements SwingConstants 50 { 51 /** 52 * The direction of the arrow. One of 53 * {@code SwingConstants.NORTH}, {@code SwingConstants.SOUTH}, 54 * {@code SwingConstants.EAST} or {@code SwingConstants.WEST}. 55 */ 56 protected int direction; 57 58 private Color shadow; 59 private Color darkShadow; 60 private Color highlight; 61 62 /** 63 * Creates a {@code BasicArrowButton} whose arrow 64 * is drawn in the specified direction and with the specified 65 * colors. 66 * 67 * @param direction the direction of the arrow; one of 68 * {@code SwingConstants.NORTH}, {@code SwingConstants.SOUTH}, 69 * {@code SwingConstants.EAST} or {@code SwingConstants.WEST} 70 * @param background the background color of the button 71 * @param shadow the color of the shadow 72 * @param darkShadow the color of the dark shadow 73 * @param highlight the color of the highlight 74 * @since 1.4 75 */ 76 public BasicArrowButton(int direction, Color background, Color shadow, 77 Color darkShadow, Color highlight) { 78 super(); 79 setRequestFocusEnabled(false); 80 setDirection(direction); 81 setBackground(background); 82 this.shadow = shadow; 83 this.darkShadow = darkShadow; 84 this.highlight = highlight; 85 } 86 87 /** 88 * Creates a {@code BasicArrowButton} whose arrow 89 * is drawn in the specified direction. 90 * 91 * @param direction the direction of the arrow; one of 92 * {@code SwingConstants.NORTH}, {@code SwingConstants.SOUTH}, 93 * {@code SwingConstants.EAST} or {@code SwingConstants.WEST} 94 */ 95 public BasicArrowButton(int direction) { 96 this(direction, UIManager.getColor("control"), UIManager.getColor("controlShadow"), 97 UIManager.getColor("controlDkShadow"), UIManager.getColor("controlLtHighlight")); 98 } 99 100 /** 101 * Returns the direction of the arrow. 102 */ 103 public int getDirection() { 104 return direction; 105 } 106 107 /** 108 * Sets the direction of the arrow. 109 * 110 * @param direction the direction of the arrow; one of 111 * of {@code SwingConstants.NORTH}, 112 * {@code SwingConstants.SOUTH}, 113 * {@code SwingConstants.EAST} or {@code SwingConstants.WEST} 114 */ 115 public void setDirection(int direction) { 116 this.direction = direction; 117 } 118 119 public void paint(Graphics g) { 120 Color origColor; 121 boolean isPressed, isEnabled; 122 int w, h, size; 123 124 w = getSize().width; 125 h = getSize().height; 126 origColor = g.getColor(); 127 isPressed = getModel().isPressed(); 128 isEnabled = isEnabled(); 129 130 g.setColor(getBackground()); 131 g.fillRect(1, 1, w-2, h-2); 132 133 /// Draw the proper Border 134 if (getBorder() != null && !(getBorder() instanceof UIResource)) { 135 paintBorder(g); 136 } else if (isPressed) { 137 g.setColor(shadow); 138 g.drawRect(0, 0, w-1, h-1); 139 } else { 140 // Using the background color set above 141 g.drawLine(0, 0, 0, h-1); 142 g.drawLine(1, 0, w-2, 0); 143 144 g.setColor(highlight); // inner 3D border 145 g.drawLine(1, 1, 1, h-3); 146 g.drawLine(2, 1, w-3, 1); 147 148 g.setColor(shadow); // inner 3D border 149 g.drawLine(1, h-2, w-2, h-2); 150 g.drawLine(w-2, 1, w-2, h-3); 151 152 g.setColor(darkShadow); // black drop shadow __| 153 g.drawLine(0, h-1, w-1, h-1); 154 g.drawLine(w-1, h-1, w-1, 0); 155 } 156 157 // If there's no room to draw arrow, bail 158 if(h < 5 || w < 5) { 159 g.setColor(origColor); 160 return; 161 } 162 163 if (isPressed) { 164 g.translate(1, 1); 165 } 166 167 // Draw the arrow 168 size = Math.min((h - 4) / 3, (w - 4) / 3); 169 size = Math.max(size, 2); 170 paintTriangle(g, (w - size) / 2, (h - size) / 2, 171 size, direction, isEnabled); 172 173 // Reset the Graphics back to it's original settings 174 if (isPressed) { 175 g.translate(-1, -1); 176 } 177 g.setColor(origColor); 178 179 } 180 181 /** 182 * Returns the preferred size of the {@code BasicArrowButton}. 183 * 184 * @return the preferred size 185 */ 186 public Dimension getPreferredSize() { 187 return new Dimension(16, 16); 188 } 189 190 /** 191 * Returns the minimum size of the {@code BasicArrowButton}. 192 * 193 * @return the minimum size 194 */ 195 public Dimension getMinimumSize() { 196 return new Dimension(5, 5); 197 } 198 199 /** 200 * Returns the maximum size of the {@code BasicArrowButton}. 201 * 202 * @return the maximum size 203 */ 204 public Dimension getMaximumSize() { 205 return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); 206 } 207 208 /** 209 * Returns whether the arrow button should get the focus. 210 * {@code BasicArrowButton}s are used as a child component of 211 * composite components such as {@code JScrollBar} and 212 * {@code JComboBox}. Since the composite component typically gets the 213 * focus, this method is overriden to return {@code false}. 214 * 215 * @return {@code false} 216 */ 217 public boolean isFocusTraversable() { 218 return false; 219 } 220 221 /** 222 * Paints a triangle. 223 * 224 * @param g the {@code Graphics} to draw to 225 * @param x the x coordinate 226 * @param y the y coordinate 227 * @param size the size of the triangle to draw 228 * @param direction the direction in which to draw the arrow; 229 * one of {@code SwingConstants.NORTH}, 230 * {@code SwingConstants.SOUTH}, {@code SwingConstants.EAST} or 231 * {@code SwingConstants.WEST} 232 * @param isEnabled whether or not the arrow is drawn enabled 233 */ 234 public void paintTriangle(Graphics g, int x, int y, int size, 235 int direction, boolean isEnabled) { 236 Color oldColor = g.getColor(); 237 int mid, i, j; 238 239 j = 0; 240 size = Math.max(size, 2); 241 mid = (size / 2) - 1; 242 243 g.translate(x, y); 244 if(isEnabled) 245 g.setColor(darkShadow); 246 else 247 g.setColor(shadow); 248 249 switch(direction) { 250 case NORTH: 251 for(i = 0; i < size; i++) { 252 g.drawLine(mid-i, i, mid+i, i); 253 } 254 if(!isEnabled) { 255 g.setColor(highlight); 256 g.drawLine(mid-i+2, i, mid+i, i); 257 } 258 break; 259 case SOUTH: 260 if(!isEnabled) { 261 g.translate(1, 1); 262 g.setColor(highlight); 263 for(i = size-1; i >= 0; i--) { 264 g.drawLine(mid-i, j, mid+i, j); 265 j++; 266 } 267 g.translate(-1, -1); 268 g.setColor(shadow); 269 } 270 271 j = 0; 272 for(i = size-1; i >= 0; i--) { 273 g.drawLine(mid-i, j, mid+i, j); 274 j++; 275 } 276 break; 277 case WEST: 278 for(i = 0; i < size; i++) { 279 g.drawLine(i, mid-i, i, mid+i); 280 } 281 if(!isEnabled) { 282 g.setColor(highlight); 283 g.drawLine(i, mid-i+2, i, mid+i); 284 } 285 break; 286 case EAST: 287 if(!isEnabled) { 288 g.translate(1, 1); 289 g.setColor(highlight); 290 for(i = size-1; i >= 0; i--) { 291 g.drawLine(j, mid-i, j, mid+i); 292 j++; 293 } 294 g.translate(-1, -1); 295 g.setColor(shadow); 296 } 297 298 j = 0; 299 for(i = size-1; i >= 0; i--) { 300 g.drawLine(j, mid-i, j, mid+i); 301 j++; 302 } 303 break; 304 } 305 g.translate(-x, -y); 306 g.setColor(oldColor); 307 } 308 309 }