001/* MetalButtonUI.java
002   Copyright (C) 2005 Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.swing.plaf.metal;
040
041import java.awt.Color;
042import java.awt.Component;
043import java.awt.Font;
044import java.awt.FontMetrics;
045import java.awt.Graphics;
046import java.awt.Rectangle;
047
048import javax.swing.AbstractButton;
049import javax.swing.ButtonModel;
050import javax.swing.JButton;
051import javax.swing.JComponent;
052import javax.swing.JToolBar;
053import javax.swing.SwingConstants;
054import javax.swing.UIManager;
055import javax.swing.plaf.ComponentUI;
056import javax.swing.plaf.UIResource;
057import javax.swing.plaf.basic.BasicButtonUI;
058
059/**
060 * A UI delegate for the {@link JButton} component.
061 *
062 * @author Roman Kennke (roman@kennke.org)
063 */
064public class MetalButtonUI
065  extends BasicButtonUI
066{
067
068  /**
069   * The shared button UI.
070   */
071  private static MetalButtonUI sharedUI;
072
073  /**
074   * The color used to draw the focus rectangle around the text and/or icon.
075   */
076  protected Color focusColor;
077
078  /**
079   * The background color for the button when it is pressed.
080   */
081  protected Color selectColor;
082
083  /**
084   * The color for disabled button labels.
085   */
086  protected Color disabledTextColor;
087
088  /**
089   * Returns a UI delegate for the specified component.
090   *
091   * @param c  the component (should be a subclass of {@link AbstractButton}).
092   *
093   * @return A new instance of <code>MetalButtonUI</code>.
094   */
095  public static ComponentUI createUI(JComponent c)
096  {
097    if (sharedUI == null)
098      sharedUI = new MetalButtonUI();
099    return sharedUI;
100  }
101
102  /**
103   * Creates a new instance.
104   */
105  public MetalButtonUI()
106  {
107    super();
108  }
109
110  /**
111   * Returns the color for the focus border.
112   *
113   * @return the color for the focus border
114   */
115  protected Color getFocusColor()
116  {
117    focusColor = UIManager.getColor(getPropertyPrefix() + "focus");
118    return focusColor;
119  }
120
121  /**
122   * Returns the color that indicates a selected button.
123   *
124   * @return the color that indicates a selected button
125   */
126  protected Color getSelectColor()
127  {
128    selectColor = UIManager.getColor(getPropertyPrefix() + "select");
129    return selectColor;
130  }
131
132  /**
133   * Returns the color for the text label of disabled buttons.
134   *
135   * @return the color for the text label of disabled buttons
136   */
137  protected Color getDisabledTextColor()
138  {
139    disabledTextColor = UIManager.getColor(getPropertyPrefix()
140                                           + "disabledText");
141    return disabledTextColor;
142  }
143
144  /**
145   * Installs the default settings for the specified button.
146   *
147   * @param button  the button.
148   *
149   * @see #uninstallDefaults(AbstractButton)
150   */
151  public void installDefaults(AbstractButton button)
152  {
153    // This is overridden to be public, for whatever reason.
154    super.installDefaults(button);
155  }
156
157  /**
158   * Removes the defaults added by {@link #installDefaults(AbstractButton)}.
159   */
160  public void uninstallDefaults(AbstractButton button)
161  {
162    // This is overridden to be public, for whatever reason.
163    super.uninstallDefaults(button);
164  }
165
166  /**
167   * Paints the background of the button to indicate that it is in the
168   * "pressed" state.
169   *
170   * @param g  the graphics context.
171   * @param b  the button.
172   */
173  protected void paintButtonPressed(Graphics g, AbstractButton b)
174  {
175    if (b.isContentAreaFilled())
176    {
177      g.setColor(getSelectColor());
178      g.fillRect(0, 0, b.getWidth(), b.getHeight());
179    }
180  }
181
182  /**
183   * Paints the focus rectangle around the button text and/or icon.
184   *
185   * @param g  the graphics context.
186   * @param b  the button.
187   * @param viewRect  the button bounds.
188   * @param textRect  the text bounds.
189   * @param iconRect  the icon bounds.
190   */
191  protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect,
192          Rectangle textRect, Rectangle iconRect)
193  {
194    if (b.isEnabled() && b.hasFocus() && b.isFocusPainted())
195    {
196      Color savedColor = g.getColor();
197      g.setColor(getFocusColor());
198      Rectangle focusRect = iconRect.union(textRect);
199      g.drawRect(focusRect.x - 1, focusRect.y,
200                 focusRect.width + 1, focusRect.height);
201      g.setColor(savedColor);
202    }
203  }
204
205  /**
206   * Paints the button text.
207   *
208   * @param g  the graphics context.
209   * @param c  the button.
210   * @param textRect  the text bounds.
211   * @param text  the text to display.
212   */
213  protected void paintText(Graphics g, JComponent c, Rectangle textRect,
214          String text)
215  {
216    AbstractButton b = (AbstractButton) c;
217    Font f = b.getFont();
218    g.setFont(f);
219    FontMetrics fm = g.getFontMetrics(f);
220
221    if (b.isEnabled())
222      {
223        g.setColor(b.getForeground());
224        g.drawString(text, textRect.x, textRect.y + fm.getAscent());
225      }
226    else
227      {
228        g.setColor(getDisabledTextColor());
229        g.drawString(text, textRect.x, textRect.y + fm.getAscent());
230      }
231  }
232
233  /**
234   * If the property <code>Button.gradient</code> is set, then a gradient is
235   * painted as background, otherwise the normal superclass behaviour is
236   * called.
237   */
238  public void update(Graphics g, JComponent c)
239  {
240    AbstractButton b = (AbstractButton) c;
241    if ((b.getBackground() instanceof UIResource)
242        && b.isContentAreaFilled() && b.isEnabled())
243      {
244        ButtonModel m = b.getModel();
245        String uiKey = "Button.gradient";
246        if (! isToolbarButton(b))
247          {
248            if (! m.isArmed() && ! m.isPressed() && isDrawingGradient(uiKey))
249              {
250                MetalUtils.paintGradient(g, 0, 0, b.getWidth(), b.getHeight(),
251                                         SwingConstants.VERTICAL,
252                                         uiKey);
253                paint(g, c);
254                return;
255              }
256          }
257        else if (m.isRollover() && isDrawingGradient(uiKey))
258          {
259            MetalUtils.paintGradient(g, 0, 0, b.getWidth(), b.getHeight(),
260                                     SwingConstants.VERTICAL,
261                                     uiKey);
262            paint(g, c);
263            return;
264          }
265      }
266    // Fallback if we didn't have any of the two above cases.
267    super.update(g, c);
268  }
269
270  /**
271   * Returns <code>true</code> when the button is a toolbar button,
272   * <code>false</code> otherwise.
273   *
274   * @param b the button component to test
275   *
276   * @return <code>true</code> when the button is a toolbar button,
277   *         <code>false</code> otherwise
278   */
279  private boolean isToolbarButton(Component b)
280  {
281    Component parent = b.getParent();
282    return parent instanceof JToolBar;
283  }
284
285  /**
286   * Returns <code>true</code> if we should draw the button gradient,
287   * <code>false</code> otherwise.
288   *
289   * @param uiKey the UIManager key for the gradient
290   *
291   * @return <code>true</code> if we should draw the button gradient,
292   *         <code>false</code> otherwise
293   */
294  private boolean isDrawingGradient(String uiKey)
295  {
296    return (UIManager.get(uiKey) != null);
297  }
298}