1 /*
   2  * Copyright (c) 1998, 2019, 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 
  26 package javax.swing.plaf.metal;
  27 
  28 import sun.swing.SwingUtilities2;
  29 import sun.awt.AppContext;
  30 
  31 import java.awt.*;
  32 import java.awt.event.*;
  33 import java.lang.ref.*;
  34 import java.util.*;
  35 import javax.swing.plaf.basic.BasicToggleButtonUI;
  36 
  37 import javax.swing.*;
  38 import javax.swing.border.*;
  39 import javax.swing.plaf.*;
  40 import javax.swing.*;
  41 
  42 import java.io.Serializable;
  43 
  44 /**
  45  * MetalToggleButton implementation
  46  * <p>
  47  * <strong>Warning:</strong>
  48  * Serialized objects of this class will not be compatible with
  49  * future Swing releases. The current serialization support is
  50  * appropriate for short term storage or RMI between applications running
  51  * the same version of Swing.  As of 1.4, support for long term storage
  52  * of all JavaBeans
  53  * has been added to the <code>java.beans</code> package.
  54  * Please see {@link java.beans.XMLEncoder}.
  55  *
  56  * @author Tom Santos
  57  */
  58 @SuppressWarnings("serial") // Same-version serialization only
  59 public class MetalToggleButtonUI extends BasicToggleButtonUI {
  60 
  61     private static final Object METAL_TOGGLE_BUTTON_UI_KEY = new Object();
  62 
  63     /**
  64      * The color of a focused toggle button.
  65      */
  66     protected Color focusColor;
  67 
  68     /**
  69      * The color of a selected button.
  70      */
  71     protected Color selectColor;
  72 
  73     /**
  74      * The color of a disabled text.
  75      */
  76     protected Color disabledTextColor;
  77 
  78     private boolean defaults_initialized = false;
  79 
  80     // ********************************
  81     //        Create PLAF
  82     // ********************************
  83 
  84     /**
  85      * Constructs the {@code MetalToogleButtonUI}.
  86      *
  87      * @param b a component
  88      * @return the {@code MetalToogleButtonUI}.
  89      */
  90     public static ComponentUI createUI(JComponent b) {
  91         AppContext appContext = AppContext.getAppContext();
  92         MetalToggleButtonUI metalToggleButtonUI =
  93                 (MetalToggleButtonUI) appContext.get(METAL_TOGGLE_BUTTON_UI_KEY);
  94         if (metalToggleButtonUI == null) {
  95             metalToggleButtonUI = new MetalToggleButtonUI();
  96             appContext.put(METAL_TOGGLE_BUTTON_UI_KEY, metalToggleButtonUI);
  97         }
  98         return metalToggleButtonUI;
  99     }
 100 
 101     // ********************************
 102     //        Install Defaults
 103     // ********************************
 104     public void installDefaults(AbstractButton b) {
 105         super.installDefaults(b);
 106         if(!defaults_initialized) {
 107             focusColor = UIManager.getColor(getPropertyPrefix() + "focus");
 108             selectColor = UIManager.getColor(getPropertyPrefix() + "select");
 109             disabledTextColor = UIManager.getColor(getPropertyPrefix() + "disabledText");
 110             defaults_initialized = true;
 111         }
 112     }
 113 
 114     protected void uninstallDefaults(AbstractButton b) {
 115         super.uninstallDefaults(b);
 116         defaults_initialized = false;
 117     }
 118 
 119     // ********************************
 120     //         Default Accessors
 121     // ********************************
 122     /**
 123      * Returns the color of a selected button.
 124      *
 125      * @return the color of a selected button
 126      */
 127     protected Color getSelectColor() {
 128         return selectColor;
 129     }
 130 
 131     /**
 132      * Returns the color of a disabled text.
 133      *
 134      * @return the color of a disabled text
 135      */
 136     protected Color getDisabledTextColor() {
 137         return disabledTextColor;
 138     }
 139 
 140     /**
 141      * Returns the color of a focused toggle button.
 142      *
 143      * @return the color of a focused toggle button
 144      */
 145     protected Color getFocusColor() {
 146         return focusColor;
 147     }
 148 
 149 
 150     // ********************************
 151     //        Paint Methods
 152     // ********************************
 153     /**
 154      * If necessary paints the background of the component, then invokes
 155      * <code>paint</code>.
 156      *
 157      * @param g Graphics to paint to
 158      * @param c JComponent painting on
 159      * @throws NullPointerException if <code>g</code> or <code>c</code> is
 160      *         null
 161      * @see javax.swing.plaf.ComponentUI#update
 162      * @see javax.swing.plaf.ComponentUI#paint
 163      * @since 1.5
 164      */
 165     public void update(Graphics g, JComponent c) {
 166         AbstractButton button = (AbstractButton)c;
 167         if ((c.getBackground() instanceof UIResource) &&
 168                         button.isContentAreaFilled() && c.isEnabled()) {
 169             ButtonModel model = button.getModel();
 170             if (!MetalUtils.isToolBarButton(c)) {
 171                 if (!model.isArmed() && !model.isPressed() &&
 172                         MetalUtils.drawGradient(
 173                         c, g, "ToggleButton.gradient", 0, 0, c.getWidth(),
 174                         c.getHeight(), true)) {
 175                     paint(g, c);
 176                     return;
 177                 }
 178             }
 179             else if ((model.isRollover() || model.isSelected()) &&
 180                         MetalUtils.drawGradient(c, g, "ToggleButton.gradient",
 181                         0, 0, c.getWidth(), c.getHeight(), true)) {
 182                 paint(g, c);
 183                 return;
 184             }
 185         }
 186         super.update(g, c);
 187     }
 188 
 189     protected void paintButtonPressed(Graphics g, AbstractButton b) {
 190         if ( b.isContentAreaFilled() ) {
 191             g.setColor(getSelectColor());
 192             g.fillRect(0, 0, b.getWidth(), b.getHeight());
 193         }
 194     }
 195 
 196     protected void paintText(Graphics g, JComponent c, Rectangle textRect, String text) {
 197         AbstractButton b = (AbstractButton) c;
 198         ButtonModel model = b.getModel();
 199         FontMetrics fm = SwingUtilities2.getFontMetrics(b, g);
 200         int mnemIndex = b.getDisplayedMnemonicIndex();
 201 
 202         /* Draw the Text */
 203         if(model.isEnabled()) {
 204             /*** paint the text normally */
 205             g.setColor(b.getForeground());
 206         }
 207         else {
 208             /*** paint the text disabled ***/
 209             if (model.isSelected()) {
 210                 g.setColor(c.getBackground());
 211             } else {
 212                 g.setColor(getDisabledTextColor());
 213             }
 214         }
 215         SwingUtilities2.drawStringUnderlineCharAt(c, g, text, mnemIndex,
 216                 textRect.x, textRect.y + fm.getAscent());
 217     }
 218 
 219     protected void paintFocus(Graphics g, AbstractButton b,
 220                               Rectangle viewRect, Rectangle textRect, Rectangle iconRect){
 221 
 222         Rectangle focusRect = new Rectangle();
 223         String text = b.getText();
 224         boolean isIcon = b.getIcon() != null;
 225 
 226         // If there is text
 227         if ( text != null && !text.isEmpty()) {
 228             if ( !isIcon ) {
 229                 focusRect.setBounds( textRect );
 230             }
 231             else {
 232                 focusRect.setBounds( iconRect.union( textRect ) );
 233             }
 234         }
 235         // If there is an icon and no text
 236         else if ( isIcon ) {
 237             focusRect.setBounds( iconRect );
 238         }
 239 
 240         g.setColor(getFocusColor());
 241         g.drawRect((focusRect.x-1), (focusRect.y-1),
 242                   focusRect.width+1, focusRect.height+1);
 243 
 244     }
 245 
 246     /**
 247      * Paints the appropriate icon of the button <code>b</code> in the
 248      * space <code>iconRect</code>.
 249      *
 250      * @param g Graphics to paint to
 251      * @param b Button to render for
 252      * @param iconRect space to render in
 253      * @throws NullPointerException if any of the arguments are null.
 254      * @since 1.5
 255      */
 256     protected void paintIcon(Graphics g, AbstractButton b, Rectangle iconRect) {
 257         super.paintIcon(g, b, iconRect);
 258     }
 259 }