Frames | No Frames |
1: /* BasicArrowButton.java -- 2: Copyright (C) 2004, 2005 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: import java.awt.Rectangle; 46: 47: import javax.swing.ButtonModel; 48: import javax.swing.JButton; 49: import javax.swing.SwingConstants; 50: 51: /** 52: * A button that displays an arrow (triangle) that points {@link #NORTH}, 53: * {@link #SOUTH}, {@link #EAST} or {@link #WEST}. This button is used by 54: * the {@link BasicComboBoxUI} class. 55: * 56: * @see BasicComboBoxUI#createArrowButton 57: */ 58: public class BasicArrowButton extends JButton implements SwingConstants 59: { 60: 61: /** 62: * The direction that the arrow points. 63: * 64: * @see #getDirection() 65: */ 66: protected int direction; 67: 68: /** 69: * The color the arrow is painted in if disabled and the bottom and right 70: * edges of the button. 71: * This is package-private to avoid an accessor method. 72: */ 73: transient Color shadow = Color.GRAY; 74: 75: /** 76: * The color the arrow is painted in if enabled and the bottom and right 77: * edges of the button. 78: * This is package-private to avoid an accessor method. 79: */ 80: transient Color darkShadow = new Color(102, 102, 102); 81: 82: /** 83: * The top and left edges of the button. 84: * This is package-private to avoid an accessor method. 85: */ 86: transient Color highlight = Color.WHITE; 87: 88: /** 89: * Creates a new <code>BasicArrowButton</code> object. 90: * 91: * @param direction The direction the arrow points in (one of: 92: * {@link #NORTH}, {@link #SOUTH}, {@link #EAST} and {@link #WEST}). 93: */ 94: public BasicArrowButton(int direction) 95: { 96: super(); 97: setDirection(direction); 98: } 99: 100: /** 101: * Creates a new BasicArrowButton object with the given colors and 102: * direction. 103: * 104: * @param direction The direction to point in (one of: 105: * {@link #NORTH}, {@link #SOUTH}, {@link #EAST} and {@link #WEST}). 106: * @param background The background color. 107: * @param shadow The shadow color. 108: * @param darkShadow The dark shadow color. 109: * @param highlight The highlight color. 110: */ 111: public BasicArrowButton(int direction, Color background, Color shadow, 112: Color darkShadow, Color highlight) 113: { 114: this(direction); 115: setBackground(background); 116: this.shadow = shadow; 117: this.darkShadow = darkShadow; 118: this.highlight = highlight; 119: // Mark the button as not closing the popup, we handle this ourselves. 120: putClientProperty(BasicLookAndFeel.DONT_CANCEL_POPUP, Boolean.TRUE); 121: } 122: 123: /** 124: * Returns whether the focus can traverse to this component. This method 125: * always returns <code>false</code>. 126: * 127: * @return <code>false</code>. 128: */ 129: public boolean isFocusTraversable() 130: { 131: return false; 132: } 133: 134: /** 135: * Returns the direction of the arrow (one of: {@link #NORTH}, 136: * {@link #SOUTH}, {@link #EAST} and {@link #WEST}). 137: * 138: * @return The direction of the arrow. 139: */ 140: public int getDirection() 141: { 142: return direction; 143: } 144: 145: /** 146: * Sets the direction of the arrow. 147: * 148: * @param dir The new direction of the arrow (one of: {@link #NORTH}, 149: * {@link #SOUTH}, {@link #EAST} and {@link #WEST}). 150: */ 151: public void setDirection(int dir) 152: { 153: this.direction = dir; 154: } 155: 156: /** 157: * Paints the arrow button. The painting is delegated to the 158: * paintTriangle method. 159: * 160: * @param g The Graphics object to paint with. 161: */ 162: public void paint(Graphics g) 163: { 164: super.paint(g); 165: Rectangle bounds = getBounds(); 166: int size = bounds.height / 4; 167: int x = bounds.x + (bounds.width - size) / 2; 168: int y = (bounds.height - size) / 4; 169: ButtonModel m = getModel(); 170: if (m.isArmed()) 171: { 172: x++; 173: y++; 174: } 175: paintTriangle(g, x, y, size, direction, isEnabled()); 176: } 177: 178: /** The preferred size for the button. */ 179: private static final Dimension PREFERRED_SIZE = new Dimension(16, 16); 180: 181: /** The minimum size for the button. */ 182: private static final Dimension MINIMUM_SIZE = new Dimension(5, 5); 183: 184: /** The maximum size for the button. */ 185: private static final Dimension MAXIMUM_SIZE 186: = new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); 187: 188: /** 189: * Returns the preferred size of the arrow button. 190: * 191: * @return The preferred size (always 16 x 16). 192: */ 193: public Dimension getPreferredSize() 194: { 195: return PREFERRED_SIZE; 196: } 197: 198: /** 199: * Returns the minimum size of the arrow button. 200: * 201: * @return The minimum size (always 5 x 5). 202: */ 203: public Dimension getMinimumSize() 204: { 205: return MINIMUM_SIZE; 206: } 207: 208: /** 209: * Returns the maximum size of the arrow button. 210: * 211: * @return The maximum size. 212: */ 213: public Dimension getMaximumSize() 214: { 215: return MAXIMUM_SIZE; 216: } 217: 218: /** 219: * Paints a triangle with the given size, location and direction. It is 220: * difficult to explain the rationale behind the positioning of the triangle 221: * relative to the given (x, y) position - by trial and error we seem to 222: * match the behaviour of the reference implementation (which is missing a 223: * specification for this method). 224: * 225: * @param g the graphics device. 226: * @param x the x-coordinate for the triangle's location. 227: * @param y the y-coordinate for the triangle's location. 228: * @param size the arrow size (depth). 229: * @param direction the direction of the arrow (one of: {@link #NORTH}, 230: * {@link #SOUTH}, {@link #EAST} and {@link #WEST}). 231: * @param isEnabled if <code>true</code> the arrow is drawn in the enabled 232: * state, otherwise it is drawn in the disabled state. 233: */ 234: public void paintTriangle(Graphics g, int x, int y, int size, int direction, 235: boolean isEnabled) 236: { 237: Color savedColor = g.getColor(); 238: switch (direction) 239: { 240: case NORTH: 241: paintTriangleNorth(g, x, y, size, isEnabled); 242: break; 243: case SOUTH: 244: paintTriangleSouth(g, x, y, size, isEnabled); 245: break; 246: case LEFT: 247: case WEST: 248: paintTriangleWest(g, x, y, size, isEnabled); 249: break; 250: case RIGHT: 251: case EAST: 252: paintTriangleEast(g, x, y, size, isEnabled); 253: break; 254: } 255: g.setColor(savedColor); 256: } 257: 258: /** 259: * Paints an upward-pointing triangle. This method is called by the 260: * {@link #paintTriangle(Graphics, int, int, int, int, boolean)} method. 261: * 262: * @param g the graphics device. 263: * @param x the x-coordinate for the anchor point. 264: * @param y the y-coordinate for the anchor point. 265: * @param size the arrow size (depth). 266: * @param isEnabled if <code>true</code> the arrow is drawn in the enabled 267: * state, otherwise it is drawn in the disabled state. 268: */ 269: private void paintTriangleNorth(Graphics g, int x, int y, int size, 270: boolean isEnabled) 271: { 272: int tipX = x + (size - 2) / 2; 273: int tipY = y; 274: int baseX1 = tipX - (size - 1); 275: int baseX2 = tipX + (size - 1); 276: int baseY = y + (size - 1); 277: Polygon triangle = new Polygon(); 278: triangle.addPoint(tipX, tipY); 279: triangle.addPoint(baseX1, baseY); 280: triangle.addPoint(baseX2, baseY); 281: if (isEnabled) 282: { 283: g.setColor(Color.DARK_GRAY); 284: g.fillPolygon(triangle); 285: g.drawPolygon(triangle); 286: } 287: else 288: { 289: g.setColor(Color.GRAY); 290: g.fillPolygon(triangle); 291: g.drawPolygon(triangle); 292: g.setColor(Color.WHITE); 293: g.drawLine(baseX1 + 1, baseY + 1, baseX2 + 1, baseY + 1); 294: } 295: } 296: 297: /** 298: * Paints an downward-pointing triangle. This method is called by the 299: * {@link #paintTriangle(Graphics, int, int, int, int, boolean)} method. 300: * 301: * @param g the graphics device. 302: * @param x the x-coordinate for the anchor point. 303: * @param y the y-coordinate for the anchor point. 304: * @param size the arrow size (depth). 305: * @param isEnabled if <code>true</code> the arrow is drawn in the enabled 306: * state, otherwise it is drawn in the disabled state. 307: */ 308: private void paintTriangleSouth(Graphics g, int x, int y, int size, 309: boolean isEnabled) 310: { 311: int tipX = x + (size - 2) / 2; 312: int tipY = y + (size - 1); 313: int baseX1 = tipX - (size - 1); 314: int baseX2 = tipX + (size - 1); 315: int baseY = y; 316: Polygon triangle = new Polygon(); 317: triangle.addPoint(tipX, tipY); 318: triangle.addPoint(baseX1, baseY); 319: triangle.addPoint(baseX2, baseY); 320: if (isEnabled) 321: { 322: g.setColor(Color.DARK_GRAY); 323: g.fillPolygon(triangle); 324: g.drawPolygon(triangle); 325: } 326: else 327: { 328: g.setColor(Color.GRAY); 329: g.fillPolygon(triangle); 330: g.drawPolygon(triangle); 331: g.setColor(Color.WHITE); 332: g.drawLine(tipX + 1, tipY, baseX2, baseY + 1); 333: g.drawLine(tipX + 1, tipY + 1, baseX2 + 1, baseY + 1); 334: } 335: } 336: 337: /** 338: * Paints a right-pointing triangle. This method is called by the 339: * {@link #paintTriangle(Graphics, int, int, int, int, boolean)} method. 340: * 341: * @param g the graphics device. 342: * @param x the x-coordinate for the anchor point. 343: * @param y the y-coordinate for the anchor point. 344: * @param size the arrow size (depth). 345: * @param isEnabled if <code>true</code> the arrow is drawn in the enabled 346: * state, otherwise it is drawn in the disabled state. 347: */ 348: private void paintTriangleEast(Graphics g, int x, int y, int size, 349: boolean isEnabled) 350: { 351: int tipX = x + (size - 1); 352: int tipY = y + (size - 2) / 2; 353: int baseX = x; 354: int baseY1 = tipY - (size - 1); 355: int baseY2 = tipY + (size - 1); 356: 357: Polygon triangle = new Polygon(); 358: triangle.addPoint(tipX, tipY); 359: triangle.addPoint(baseX, baseY1); 360: triangle.addPoint(baseX, baseY2); 361: if (isEnabled) 362: { 363: g.setColor(Color.DARK_GRAY); 364: g.fillPolygon(triangle); 365: g.drawPolygon(triangle); 366: } 367: else 368: { 369: g.setColor(Color.GRAY); 370: g.fillPolygon(triangle); 371: g.drawPolygon(triangle); 372: g.setColor(Color.WHITE); 373: g.drawLine(baseX + 1, baseY2, tipX, tipY + 1); 374: g.drawLine(baseX + 1, baseY2 + 1, tipX + 1, tipY + 1); 375: } 376: } 377: 378: /** 379: * Paints a left-pointing triangle. This method is called by the 380: * {@link #paintTriangle(Graphics, int, int, int, int, boolean)} method. 381: * 382: * @param g the graphics device. 383: * @param x the x-coordinate for the anchor point. 384: * @param y the y-coordinate for the anchor point. 385: * @param size the arrow size (depth). 386: * @param isEnabled if <code>true</code> the arrow is drawn in the enabled 387: * state, otherwise it is drawn in the disabled state. 388: */ 389: private void paintTriangleWest(Graphics g, int x, int y, int size, 390: boolean isEnabled) 391: { 392: int tipX = x; 393: int tipY = y + (size - 2) / 2; 394: int baseX = x + (size - 1); 395: int baseY1 = tipY - (size - 1); 396: int baseY2 = tipY + (size - 1); 397: 398: Polygon triangle = new Polygon(); 399: triangle.addPoint(tipX, tipY); 400: triangle.addPoint(baseX, baseY1); 401: triangle.addPoint(baseX, baseY2); 402: if (isEnabled) 403: { 404: g.setColor(Color.DARK_GRAY); 405: g.fillPolygon(triangle); 406: g.drawPolygon(triangle); 407: } 408: else 409: { 410: g.setColor(Color.GRAY); 411: g.fillPolygon(triangle); 412: g.drawPolygon(triangle); 413: g.setColor(Color.WHITE); 414: g.drawLine(baseX + 1, baseY1 + 1, baseX + 1, baseY2 + 1); 415: } 416: } 417: 418: }