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 * @return the direction of the arrow 104 */ 105 public int getDirection() { 106 return direction; 107 } 108 109 /** 110 * Sets the direction of the arrow. 111 * 112 * @param direction the direction of the arrow; one of 113 * of {@code SwingConstants.NORTH}, 114 * {@code SwingConstants.SOUTH}, 115 * {@code SwingConstants.EAST} or {@code SwingConstants.WEST} 116 */ 117 public void setDirection(int direction) { 118 this.direction = direction; 119 } 120 121 public void paint(Graphics g) { 122 Color origColor; 123 boolean isPressed, isEnabled; 124 int w, h, size; 125 126 w = getSize().width; 127 h = getSize().height; 128 origColor = g.getColor(); 129 isPressed = getModel().isPressed(); 130 isEnabled = isEnabled(); 131 132 g.setColor(getBackground()); 133 g.fillRect(1, 1, w-2, h-2); 134 135 /// Draw the proper Border 136 if (getBorder() != null && !(getBorder() instanceof UIResource)) { 137 paintBorder(g); 138 } else if (isPressed) { 139 g.setColor(shadow); 140 g.drawRect(0, 0, w-1, h-1); 141 } else { 142 // Using the background color set above 143 g.drawLine(0, 0, 0, h-1); 144 g.drawLine(1, 0, w-2, 0); 145 146 g.setColor(highlight); // inner 3D border 147 g.drawLine(1, 1, 1, h-3); 148 g.drawLine(2, 1, w-3, 1); 149 150 g.setColor(shadow); // inner 3D border 151 g.drawLine(1, h-2, w-2, h-2); 152 g.drawLine(w-2, 1, w-2, h-3); 153 154 g.setColor(darkShadow); // black drop shadow __| 155 g.drawLine(0, h-1, w-1, h-1); 156 g.drawLine(w-1, h-1, w-1, 0); 157 } 158 159 // If there's no room to draw arrow, bail 160 if(h < 5 || w < 5) { 161 g.setColor(origColor); 162 return; 163 } 164 165 if (isPressed) { 166 g.translate(1, 1); 167 } 168 169 // Draw the arrow 170 size = Math.min((h - 4) / 3, (w - 4) / 3); 171 size = Math.max(size, 2); 172 paintTriangle(g, (w - size) / 2, (h - size) / 2, 173 size, direction, isEnabled); 174 175 // Reset the Graphics back to it's original settings 176 if (isPressed) { 177 g.translate(-1, -1); 178 } 179 g.setColor(origColor); 180 181 } 182 183 /** 184 * Returns the preferred size of the {@code BasicArrowButton}. 185 * 186 * @return the preferred size 187 */ 188 public Dimension getPreferredSize() { 189 return new Dimension(16, 16); 190 } 191 192 /** 193 * Returns the minimum size of the {@code BasicArrowButton}. 194 * 195 * @return the minimum size 196 */ 197 public Dimension getMinimumSize() { 198 return new Dimension(5, 5); 199 } 200 201 /** 202 * Returns the maximum size of the {@code BasicArrowButton}. 203 * 204 * @return the maximum size 205 */ 206 public Dimension getMaximumSize() { 207 return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); 208 } 209 210 /** 211 * Returns whether the arrow button should get the focus. 212 * {@code BasicArrowButton}s are used as a child component of 213 * composite components such as {@code JScrollBar} and 214 * {@code JComboBox}. Since the composite component typically gets the 215 * focus, this method is overriden to return {@code false}. 216 * 217 * @return {@code false} 218 */ 219 @SuppressWarnings("deprecation") 220 public boolean isFocusTraversable() { 221 return false; 222 } 223 224 /** 225 * Paints a triangle. 226 * 227 * @param g the {@code Graphics} to draw to 228 * @param x the x coordinate 229 * @param y the y coordinate 230 * @param size the size of the triangle to draw 231 * @param direction the direction in which to draw the arrow; 232 * one of {@code SwingConstants.NORTH}, 233 * {@code SwingConstants.SOUTH}, {@code SwingConstants.EAST} or 234 * {@code SwingConstants.WEST} 235 * @param isEnabled whether or not the arrow is drawn enabled 236 */ 237 public void paintTriangle(Graphics g, int x, int y, int size, 238 int direction, boolean isEnabled) { 239 Color oldColor = g.getColor(); 240 int mid, i, j; 241 242 j = 0; 243 size = Math.max(size, 2); 244 mid = (size / 2) - 1; 245 246 g.translate(x, y); 247 if(isEnabled) 248 g.setColor(darkShadow); 249 else 250 g.setColor(shadow); 251 252 switch(direction) { 253 case NORTH: 254 for(i = 0; i < size; i++) { 255 g.drawLine(mid-i, i, mid+i, i); 256 } 257 if(!isEnabled) { 258 g.setColor(highlight); 259 g.drawLine(mid-i+2, i, mid+i, i); 260 } 261 break; 262 case SOUTH: 263 if(!isEnabled) { 264 g.translate(1, 1); 265 g.setColor(highlight); 266 for(i = size-1; i >= 0; i--) { 267 g.drawLine(mid-i, j, mid+i, j); 268 j++; 269 } 270 g.translate(-1, -1); 271 g.setColor(shadow); 272 } 273 274 j = 0; 275 for(i = size-1; i >= 0; i--) { 276 g.drawLine(mid-i, j, mid+i, j); 277 j++; 278 } 279 break; 280 case WEST: 281 for(i = 0; i < size; i++) { 282 g.drawLine(i, mid-i, i, mid+i); 283 } 284 if(!isEnabled) { 285 g.setColor(highlight); 286 g.drawLine(i, mid-i+2, i, mid+i); 287 } 288 break; 289 case EAST: 290 if(!isEnabled) { 291 g.translate(1, 1); 292 g.setColor(highlight); 293 for(i = size-1; i >= 0; i--) { 294 g.drawLine(j, mid-i, j, mid+i); 295 j++; 296 } 297 g.translate(-1, -1); 298 g.setColor(shadow); 299 } 300 301 j = 0; 302 for(i = size-1; i >= 0; i--) { 303 g.drawLine(j, mid-i, j, mid+i); 304 j++; 305 } 306 break; 307 } 308 g.translate(-x, -y); 309 g.setColor(oldColor); 310 } 311 312 }