Frames | No Frames |
1: /* BasicArrowButton.java -- 2: Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.swing.plaf.basic; 40: 41: import java.awt.Color; 42: import java.awt.Dimension; 43: import java.awt.Graphics; 44: import java.awt.Polygon; 45: 46: import javax.swing.ButtonModel; 47: import javax.swing.JButton; 48: import javax.swing.SwingConstants; 49: 50: /** 51: * A button that displays an arrow (triangle) that points {@link #NORTH}, 52: * {@link #SOUTH}, {@link #EAST} or {@link #WEST}. This button is used by 53: * the {@link BasicComboBoxUI} class. 54: * 55: * @see BasicComboBoxUI#createArrowButton 56: */ 57: public class BasicArrowButton extends JButton implements SwingConstants 58: { 59: 60: /** 61: * The direction that the arrow points. 62: * 63: * @see #getDirection() 64: */ 65: protected int direction; 66: 67: /** 68: * The color the arrow is painted in if disabled and the bottom and right 69: * edges of the button. 70: * This is package-private to avoid an accessor method. 71: */ 72: transient Color shadow = Color.GRAY; 73: 74: /** 75: * The color the arrow is painted in if enabled and the bottom and right 76: * edges of the button. 77: * This is package-private to avoid an accessor method. 78: */ 79: transient Color darkShadow = new Color(102, 102, 102); 80: 81: /** 82: * The top and left edges of the button. 83: * This is package-private to avoid an accessor method. 84: */ 85: transient Color highlight = Color.WHITE; 86: 87: /** 88: * Creates a new <code>BasicArrowButton</code> object with an arrow pointing 89: * in the specified direction. If the <code>direction</code> is not one of 90: * the specified constants, no arrow is drawn. 91: * 92: * @param direction The direction the arrow points in (one of: 93: * {@link #NORTH}, {@link #SOUTH}, {@link #EAST} and {@link #WEST}). 94: */ 95: public BasicArrowButton(int direction) 96: { 97: super(); 98: setDirection(direction); 99: setFocusable(false); 100: } 101: 102: /** 103: * Creates a new BasicArrowButton object with the given colors and 104: * direction. 105: * 106: * @param direction The direction to point in (one of: 107: * {@link #NORTH}, {@link #SOUTH}, {@link #EAST} and {@link #WEST}). 108: * @param background The background color. 109: * @param shadow The shadow color. 110: * @param darkShadow The dark shadow color. 111: * @param highlight The highlight color. 112: */ 113: public BasicArrowButton(int direction, Color background, Color shadow, 114: Color darkShadow, Color highlight) 115: { 116: this(direction); 117: setBackground(background); 118: this.shadow = shadow; 119: this.darkShadow = darkShadow; 120: this.highlight = highlight; 121: setFocusable(false); 122: } 123: 124: /** 125: * Returns whether the focus can traverse to this component. This method 126: * always returns <code>false</code>. 127: * 128: * @return <code>false</code>. 129: */ 130: public boolean isFocusTraversable() 131: { 132: return false; 133: } 134: 135: /** 136: * Returns the direction of the arrow (one of: {@link #NORTH}, 137: * {@link #SOUTH}, {@link #EAST} and {@link #WEST}). 138: * 139: * @return The direction of the arrow. 140: */ 141: public int getDirection() 142: { 143: return direction; 144: } 145: 146: /** 147: * Sets the direction of the arrow. 148: * 149: * @param dir The new direction of the arrow (one of: {@link #NORTH}, 150: * {@link #SOUTH}, {@link #EAST} and {@link #WEST}). 151: */ 152: public void setDirection(int dir) 153: { 154: this.direction = dir; 155: } 156: 157: /** 158: * Paints the arrow button. The painting is delegated to the 159: * paintTriangle method. 160: * 161: * @param g The Graphics object to paint with. 162: */ 163: public void paint(Graphics g) 164: { 165: super.paint(g); 166: 167: int height = getHeight(); 168: int size = height / 4; 169: 170: int x = (getWidth() - size) / 2; 171: int y = (height - size) / 2; 172: 173: ButtonModel m = getModel(); 174: if (m.isArmed()) 175: { 176: x++; 177: y++; 178: } 179: 180: paintTriangle(g, x, y, size, direction, isEnabled()); 181: } 182: 183: /** 184: * Returns the preferred size of the arrow button. 185: * 186: * @return The preferred size (always 16 x 16). 187: */ 188: public Dimension getPreferredSize() 189: { 190: // since Dimension is NOT immutable, we must return a new instance 191: // every time (if we return a cached value, the caller might modify it) 192: // - tests show that the reference implementation does the same. 193: return new Dimension(16, 16); 194: } 195: 196: /** 197: * Returns the minimum size of the arrow button. 198: * 199: * @return The minimum size (always 5 x 5). 200: */ 201: public Dimension getMinimumSize() 202: { 203: // since Dimension is NOT immutable, we must return a new instance 204: // every time (if we return a cached value, the caller might modify it) 205: // - tests show that the reference implementation does the same. 206: return new Dimension(5, 5); 207: } 208: 209: /** 210: * Returns the maximum size of the arrow button. 211: * 212: * @return The maximum size (always Integer.MAX_VALUE x Integer.MAX_VALUE). 213: */ 214: public Dimension getMaximumSize() 215: { 216: // since Dimension is NOT immutable, we must return a new instance 217: // every time (if we return a cached value, the caller might modify it) 218: // - tests show that the reference implementation does the same. 219: return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); 220: } 221: 222: /** 223: * Paints a triangle with the given size, location and direction. It is 224: * difficult to explain the rationale behind the positioning of the triangle 225: * relative to the given (x, y) position - by trial and error we seem to 226: * match the behaviour of the reference implementation (which is missing a 227: * specification for this method). 228: * 229: * @param g the graphics device. 230: * @param x the x-coordinate for the triangle's location. 231: * @param y the y-coordinate for the triangle's location. 232: * @param size the arrow size (depth). 233: * @param direction the direction of the arrow (one of: {@link #NORTH}, 234: * {@link #SOUTH}, {@link #EAST} and {@link #WEST}). 235: * @param isEnabled if <code>true</code> the arrow is drawn in the enabled 236: * state, otherwise it is drawn in the disabled state. 237: */ 238: public void paintTriangle(Graphics g, int x, int y, int size, int direction, 239: boolean isEnabled) 240: { 241: Color savedColor = g.getColor(); 242: switch (direction) 243: { 244: case NORTH: 245: paintTriangleNorth(g, x, y, size, isEnabled); 246: break; 247: case SOUTH: 248: paintTriangleSouth(g, x, y, size, isEnabled); 249: break; 250: case LEFT: 251: case WEST: 252: paintTriangleWest(g, x, y, size, isEnabled); 253: break; 254: case RIGHT: 255: case EAST: 256: paintTriangleEast(g, x, y, size, isEnabled); 257: break; 258: } 259: g.setColor(savedColor); 260: } 261: 262: /** 263: * Paints an upward-pointing triangle. This method is called by the 264: * {@link #paintTriangle(Graphics, int, int, int, int, boolean)} method. 265: * 266: * @param g the graphics device. 267: * @param x the x-coordinate for the anchor point. 268: * @param y the y-coordinate for the anchor point. 269: * @param size the arrow size (depth). 270: * @param isEnabled if <code>true</code> the arrow is drawn in the enabled 271: * state, otherwise it is drawn in the disabled state. 272: */ 273: private void paintTriangleNorth(Graphics g, int x, int y, int size, 274: boolean isEnabled) 275: { 276: int tipX = x + (size - 2) / 2; 277: int tipY = y; 278: int baseX1 = tipX - (size - 1); 279: int baseX2 = tipX + (size - 1); 280: int baseY = y + (size - 1); 281: Polygon triangle = new Polygon(); 282: triangle.addPoint(tipX, tipY); 283: triangle.addPoint(baseX1, baseY); 284: triangle.addPoint(baseX2, baseY); 285: if (isEnabled) 286: { 287: g.setColor(Color.DARK_GRAY); 288: g.fillPolygon(triangle); 289: g.drawPolygon(triangle); 290: } 291: else 292: { 293: g.setColor(Color.GRAY); 294: g.fillPolygon(triangle); 295: g.drawPolygon(triangle); 296: g.setColor(Color.WHITE); 297: g.drawLine(baseX1 + 1, baseY + 1, baseX2 + 1, baseY + 1); 298: } 299: } 300: 301: /** 302: * Paints an downward-pointing triangle. This method is called by the 303: * {@link #paintTriangle(Graphics, int, int, int, int, boolean)} method. 304: * 305: * @param g the graphics device. 306: * @param x the x-coordinate for the anchor point. 307: * @param y the y-coordinate for the anchor point. 308: * @param size the arrow size (depth). 309: * @param isEnabled if <code>true</code> the arrow is drawn in the enabled 310: * state, otherwise it is drawn in the disabled state. 311: */ 312: private void paintTriangleSouth(Graphics g, int x, int y, int size, 313: boolean isEnabled) 314: { 315: int tipX = x + (size - 2) / 2; 316: int tipY = y + (size - 1); 317: int baseX1 = tipX - (size - 1); 318: int baseX2 = tipX + (size - 1); 319: int baseY = y; 320: Polygon triangle = new Polygon(); 321: triangle.addPoint(tipX, tipY); 322: triangle.addPoint(baseX1, baseY); 323: triangle.addPoint(baseX2, baseY); 324: if (isEnabled) 325: { 326: g.setColor(Color.DARK_GRAY); 327: g.fillPolygon(triangle); 328: g.drawPolygon(triangle); 329: } 330: else 331: { 332: g.setColor(Color.GRAY); 333: g.fillPolygon(triangle); 334: g.drawPolygon(triangle); 335: g.setColor(Color.WHITE); 336: g.drawLine(tipX + 1, tipY, baseX2, baseY + 1); 337: g.drawLine(tipX + 1, tipY + 1, baseX2 + 1, baseY + 1); 338: } 339: } 340: 341: /** 342: * Paints a right-pointing triangle. This method is called by the 343: * {@link #paintTriangle(Graphics, int, int, int, int, boolean)} method. 344: * 345: * @param g the graphics device. 346: * @param x the x-coordinate for the anchor point. 347: * @param y the y-coordinate for the anchor point. 348: * @param size the arrow size (depth). 349: * @param isEnabled if <code>true</code> the arrow is drawn in the enabled 350: * state, otherwise it is drawn in the disabled state. 351: */ 352: private void paintTriangleEast(Graphics g, int x, int y, int size, 353: boolean isEnabled) 354: { 355: int tipX = x + (size - 1); 356: int tipY = y + (size - 2) / 2; 357: int baseX = x; 358: int baseY1 = tipY - (size - 1); 359: int baseY2 = tipY + (size - 1); 360: 361: Polygon triangle = new Polygon(); 362: triangle.addPoint(tipX, tipY); 363: triangle.addPoint(baseX, baseY1); 364: triangle.addPoint(baseX, baseY2); 365: if (isEnabled) 366: { 367: g.setColor(Color.DARK_GRAY); 368: g.fillPolygon(triangle); 369: g.drawPolygon(triangle); 370: } 371: else 372: { 373: g.setColor(Color.GRAY); 374: g.fillPolygon(triangle); 375: g.drawPolygon(triangle); 376: g.setColor(Color.WHITE); 377: g.drawLine(baseX + 1, baseY2, tipX, tipY + 1); 378: g.drawLine(baseX + 1, baseY2 + 1, tipX + 1, tipY + 1); 379: } 380: } 381: 382: /** 383: * Paints a left-pointing triangle. This method is called by the 384: * {@link #paintTriangle(Graphics, int, int, int, int, boolean)} method. 385: * 386: * @param g the graphics device. 387: * @param x the x-coordinate for the anchor point. 388: * @param y the y-coordinate for the anchor point. 389: * @param size the arrow size (depth). 390: * @param isEnabled if <code>true</code> the arrow is drawn in the enabled 391: * state, otherwise it is drawn in the disabled state. 392: */ 393: private void paintTriangleWest(Graphics g, int x, int y, int size, 394: boolean isEnabled) 395: { 396: int tipX = x; 397: int tipY = y + (size - 2) / 2; 398: int baseX = x + (size - 1); 399: int baseY1 = tipY - (size - 1); 400: int baseY2 = tipY + (size - 1); 401: 402: Polygon triangle = new Polygon(); 403: triangle.addPoint(tipX, tipY); 404: triangle.addPoint(baseX, baseY1); 405: triangle.addPoint(baseX, baseY2); 406: if (isEnabled) 407: { 408: g.setColor(Color.DARK_GRAY); 409: g.fillPolygon(triangle); 410: g.drawPolygon(triangle); 411: } 412: else 413: { 414: g.setColor(Color.GRAY); 415: g.fillPolygon(triangle); 416: g.drawPolygon(triangle); 417: g.setColor(Color.WHITE); 418: g.drawLine(baseX + 1, baseY1 + 1, baseX + 1, baseY2 + 1); 419: } 420: } 421: 422: }