GNU Classpath (0.20) | |
Frames | No Frames |
1: /* BasicButtonUI.java -- 2: Copyright (C) 2002, 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.Dimension; 42: import java.awt.Font; 43: import java.awt.FontMetrics; 44: import java.awt.Graphics; 45: import java.awt.Rectangle; 46: 47: import javax.swing.AbstractButton; 48: import javax.swing.ButtonModel; 49: import javax.swing.Icon; 50: import javax.swing.InputMap; 51: import javax.swing.JButton; 52: import javax.swing.JComponent; 53: import javax.swing.LookAndFeel; 54: import javax.swing.SwingUtilities; 55: import javax.swing.UIManager; 56: import javax.swing.plaf.ButtonUI; 57: import javax.swing.plaf.ComponentUI; 58: import javax.swing.plaf.UIResource; 59: 60: /** 61: * A UI delegate for the {@link JButton} component. 62: */ 63: public class BasicButtonUI extends ButtonUI 64: { 65: /** 66: * A constant used to pad out elements in the button's layout and 67: * preferred size calculations. 68: */ 69: protected int defaultTextIconGap = 4; 70: 71: /** 72: * A constant added to the defaultTextIconGap to adjust the text 73: * within this particular button. 74: */ 75: protected int defaultTextShiftOffset = 0; 76: 77: private int textShiftOffset; 78: 79: /** 80: * Factory method to create an instance of BasicButtonUI for a given 81: * {@link JComponent}, which should be an {@link AbstractButton}. 82: * 83: * @param c The component. 84: * 85: * @return A new UI capable of drawing the component 86: */ 87: public static ComponentUI createUI(final JComponent c) 88: { 89: return new BasicButtonUI(); 90: } 91: 92: /** 93: * Returns the default gap between the button's text and icon (in pixels). 94: * 95: * @param b the button (ignored). 96: * 97: * @return The gap. 98: */ 99: public int getDefaultTextIconGap(AbstractButton b) 100: { 101: return defaultTextIconGap; 102: } 103: 104: /** 105: * Sets the text shift offset to zero. 106: * 107: * @see #setTextShiftOffset() 108: */ 109: protected void clearTextShiftOffset() 110: { 111: textShiftOffset = 0; 112: } 113: 114: /** 115: * Returns the text shift offset. 116: * 117: * @return The text shift offset. 118: * 119: * @see #clearTextShiftOffset() 120: * @see #setTextShiftOffset() 121: */ 122: protected int getTextShiftOffset() 123: { 124: return textShiftOffset; 125: } 126: 127: /** 128: * Sets the text shift offset to the value in {@link #defaultTextShiftOffset}. 129: * 130: * @see #clearTextShiftOffset() 131: */ 132: protected void setTextShiftOffset() 133: { 134: textShiftOffset = defaultTextShiftOffset; 135: } 136: 137: /** 138: * Returns the prefix for the UI defaults property for this UI class. 139: * This is 'Button' for this class. 140: * 141: * @return the prefix for the UI defaults property 142: */ 143: protected String getPropertyPrefix() 144: { 145: return "Button."; 146: } 147: 148: /** 149: * Installs the default settings. 150: * 151: * @param b the button (<code>null</code> not permitted). 152: */ 153: protected void installDefaults(AbstractButton b) 154: { 155: String prefix = getPropertyPrefix(); 156: LookAndFeel.installColorsAndFont(b, prefix + "background", 157: prefix + "foreground", prefix + "font"); 158: LookAndFeel.installBorder(b, prefix + "border"); 159: b.setMargin(UIManager.getInsets(prefix + "margin")); 160: b.setIconTextGap(UIManager.getInt(prefix + "textIconGap")); 161: b.setInputMap(JComponent.WHEN_FOCUSED, 162: (InputMap) UIManager.get(prefix + "focusInputMap")); 163: } 164: 165: /** 166: * Removes the defaults added by {@link #installDefaults(AbstractButton)}. 167: * 168: * @param b the button (<code>null</code> not permitted). 169: */ 170: protected void uninstallDefaults(AbstractButton b) 171: { 172: if (b.getFont() instanceof UIResource) 173: b.setFont(null); 174: b.setForeground(null); 175: b.setBackground(null); 176: b.setBorder(null); 177: b.setIconTextGap(defaultTextIconGap); 178: b.setMargin(null); 179: } 180: 181: protected BasicButtonListener listener; 182: 183: /** 184: * Creates and returns a new instance of {@link BasicButtonListener}. This 185: * method provides a hook to make it easy for subclasses to install a 186: * different listener. 187: * 188: * @param b the button. 189: * 190: * @return A new listener. 191: */ 192: protected BasicButtonListener createButtonListener(AbstractButton b) 193: { 194: return new BasicButtonListener(b); 195: } 196: 197: /** 198: * Installs listeners for the button. 199: * 200: * @param b the button (<code>null</code> not permitted). 201: */ 202: protected void installListeners(AbstractButton b) 203: { 204: listener = createButtonListener(b); 205: b.addChangeListener(listener); 206: b.addPropertyChangeListener(listener); 207: b.addFocusListener(listener); 208: b.addMouseListener(listener); 209: b.addMouseMotionListener(listener); 210: } 211: 212: /** 213: * Uninstalls listeners for the button. 214: * 215: * @param b the button (<code>null</code> not permitted). 216: */ 217: protected void uninstallListeners(AbstractButton b) 218: { 219: b.removeChangeListener(listener); 220: b.removePropertyChangeListener(listener); 221: b.removeFocusListener(listener); 222: b.removeMouseListener(listener); 223: b.removeMouseMotionListener(listener); 224: } 225: 226: protected void installKeyboardActions(AbstractButton b) 227: { 228: listener.installKeyboardActions(b); 229: } 230: 231: protected void uninstallKeyboardActions(AbstractButton b) 232: { 233: listener.uninstallKeyboardActions(b); 234: } 235: 236: /** 237: * Install the BasicButtonUI as the UI for a particular component. 238: * This means registering all the UI's listeners with the component, 239: * and setting any properties of the button which are particular to 240: * this look and feel. 241: * 242: * @param c The component to install the UI into 243: */ 244: public void installUI(final JComponent c) 245: { 246: super.installUI(c); 247: if (c instanceof AbstractButton) 248: { 249: AbstractButton b = (AbstractButton) c; 250: installDefaults(b); 251: installListeners(b); 252: installKeyboardActions(b); 253: } 254: } 255: 256: /** 257: * Calculate the preferred size of this component, by delegating to 258: * {@link BasicGraphicsUtils#getPreferredButtonSize}. 259: * 260: * @param c The component to measure 261: * 262: * @return The preferred dimensions of the component 263: */ 264: public Dimension getPreferredSize(JComponent c) 265: { 266: AbstractButton b = (AbstractButton)c; 267: Dimension d = 268: BasicGraphicsUtils.getPreferredButtonSize 269: (b, defaultTextIconGap + defaultTextShiftOffset); 270: return d; 271: } 272: 273: static Icon currentIcon(AbstractButton b) 274: { 275: Icon i = b.getIcon(); 276: ButtonModel model = b.getModel(); 277: 278: if (model.isPressed() && b.getPressedIcon() != null && b.isEnabled()) 279: i = b.getPressedIcon(); 280: 281: else if (model.isRollover()) 282: { 283: if (b.isSelected() && b.getRolloverSelectedIcon() != null) 284: i = b.getRolloverSelectedIcon(); 285: else if (b.getRolloverIcon() != null) 286: i = b.getRolloverIcon(); 287: } 288: 289: else if (b.isSelected() && b.isEnabled()) 290: { 291: if (b.isEnabled() && b.getSelectedIcon() != null) 292: i = b.getSelectedIcon(); 293: else if (b.getDisabledSelectedIcon() != null) 294: i = b.getDisabledSelectedIcon(); 295: } 296: 297: else if (! b.isEnabled() && b.getDisabledIcon() != null) 298: i = b.getDisabledIcon(); 299: 300: return i; 301: } 302: 303: /** 304: * Paint the component, which is an {@link AbstractButton}, according to 305: * its current state. 306: * 307: * @param g The graphics context to paint with 308: * @param c The component to paint the state of 309: */ 310: public void paint(Graphics g, JComponent c) 311: { 312: AbstractButton b = (AbstractButton) c; 313: 314: Rectangle tr = new Rectangle(); 315: Rectangle ir = new Rectangle(); 316: Rectangle vr = new Rectangle(); 317: 318: Font f = c.getFont(); 319: 320: g.setFont(f); 321: 322: if (b.isBorderPainted()) 323: SwingUtilities.calculateInnerArea(b, vr); 324: else 325: vr = SwingUtilities.getLocalBounds(b); 326: String text = SwingUtilities.layoutCompoundLabel(c, g.getFontMetrics(f), 327: b.getText(), 328: currentIcon(b), 329: b.getVerticalAlignment(), 330: b.getHorizontalAlignment(), 331: b.getVerticalTextPosition(), 332: b.getHorizontalTextPosition(), 333: vr, ir, tr, 334: b.getIconTextGap() 335: + defaultTextShiftOffset); 336: 337: if ((b.getModel().isArmed() && b.getModel().isPressed()) 338: || b.isSelected()) 339: paintButtonPressed(g, b); 340: 341: paintIcon(g, c, ir); 342: if (text != null) 343: paintText(g, b, tr, text); 344: if (b.isFocusOwner() && b.isFocusPainted()) 345: paintFocus(g, b, vr, tr, ir); 346: } 347: 348: /** 349: * Paint any focus decoration this {@link JComponent} might have. The 350: * component, which in this case will be an {@link AbstractButton}, 351: * should only have focus decoration painted if it has the focus, and its 352: * "focusPainted" property is <code>true</code>. 353: * 354: * @param g Graphics context to paint with 355: * @param b Button to paint the focus of 356: * @param vr Visible rectangle, the area in which to paint 357: * @param tr Text rectangle, contained in visible rectangle 358: * @param ir Icon rectangle, contained in visible rectangle 359: * 360: * @see AbstractButton#isFocusPainted() 361: * @see JComponent#hasFocus() 362: */ 363: protected void paintFocus(Graphics g, AbstractButton b, Rectangle vr, 364: Rectangle tr, Rectangle ir) 365: { 366: // In the BasicLookAndFeel no focus border is drawn. This can be 367: // overridden in subclasses to implement such behaviour. 368: } 369: 370: /** 371: * Paint the icon for this component. Depending on the state of the 372: * component and the availability of the button's various icon 373: * properties, this might mean painting one of several different icons. 374: * 375: * @param g Graphics context to paint with 376: * @param c Component to paint the icon of 377: * @param iconRect Rectangle in which the icon should be painted 378: */ 379: protected void paintIcon(Graphics g, JComponent c, Rectangle iconRect) 380: { 381: AbstractButton b = (AbstractButton) c; 382: Icon i = currentIcon(b); 383: 384: if (i != null) 385: i.paintIcon(c, g, iconRect.x, iconRect.y); 386: } 387: 388: /** 389: * Paints the background area of an {@link AbstractButton} in the pressed 390: * state. This means filling the supplied area with a darker than normal 391: * background. 392: * 393: * @param g The graphics context to paint with 394: * @param b The button to paint the state of 395: */ 396: protected void paintButtonPressed(Graphics g, AbstractButton b) 397: { 398: if (b.isContentAreaFilled() && b.isOpaque()) 399: { 400: Rectangle area = new Rectangle(); 401: SwingUtilities.calculateInnerArea(b, area); 402: g.setColor(UIManager.getColor(getPropertyPrefix() + "shadow")); 403: g.fillRect(area.x, area.y, area.width, area.height); 404: } 405: } 406: 407: /** 408: * Paints the "text" property of an {@link AbstractButton}. 409: * 410: * @param g The graphics context to paint with 411: * @param c The component to paint the state of 412: * @param textRect The area in which to paint the text 413: * @param text The text to paint 414: */ 415: protected void paintText(Graphics g, JComponent c, Rectangle textRect, 416: String text) 417: { 418: paintText(g, (AbstractButton) c, textRect, text); 419: } 420: 421: /** 422: * Paints the "text" property of an {@link AbstractButton}. 423: * 424: * @param g The graphics context to paint with 425: * @param b The button to paint the state of 426: * @param textRect The area in which to paint the text 427: * @param text The text to paint 428: * 429: * @since 1.4 430: */ 431: protected void paintText(Graphics g, AbstractButton b, Rectangle textRect, 432: String text) 433: { 434: Font f = b.getFont(); 435: g.setFont(f); 436: FontMetrics fm = g.getFontMetrics(f); 437: 438: if (b.isEnabled()) 439: { 440: g.setColor(b.getForeground()); 441: g.drawString(text, textRect.x, textRect.y + fm.getAscent()); 442: } 443: else 444: { 445: String prefix = getPropertyPrefix(); 446: g.setColor(UIManager.getColor(prefix + "disabledText")); 447: g.drawString(text, textRect.x, textRect.y + fm.getAscent()); 448: } 449: } 450: }
GNU Classpath (0.20) |