All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ch.randelshofer.quaqua.QuaquaRadioButtonUI Maven / Gradle / Ivy

Go to download

A Mavenisation of the Quaqua Mac OSX Swing Look and Feel (Java library) Quaqua Look and Feel (C) 2003-2010, Werner Randelshofer. Mavenisation by Matt Gumbley, DevZendo.org - for problems with Mavenisation, see Matt; for issues with Quaqua, see the Quaqua home page. For full license details, see http://randelshofer.ch/quaqua/license.html

The newest version!
/*
 * @(#)QuaquaRadioButtonUI.java  
 *
 * Copyright (c) 2005-2010 Werner Randelshofer, Immensee, Switzerland.
 * All rights reserved.
 *
 * You may not use, copy or modify this file, except in compliance with the
 * license agreement you entered into with Werner Randelshofer.
 * For details see accompanying license terms.
 */
package ch.randelshofer.quaqua;

import ch.randelshofer.quaqua.util.*;
import ch.randelshofer.quaqua.util.Debug;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.*;
import javax.swing.plaf.*;
import javax.swing.plaf.basic.*;
import java.beans.*;
import java.util.Enumeration;
import javax.swing.text.View;

/**
 * QuaquaRadioButtonUI.
 *
 * @author  Werner Randelshofer
 * @version $Id: QuaquaRadioButtonUI.java 361 2010-11-21 11:19:20Z wrandelshofer $
 */
public class QuaquaRadioButtonUI extends BasicRadioButtonUI implements VisuallyLayoutable {

    private final static QuaquaRadioButtonUI checkboxUI = new QuaquaRadioButtonUI();
    private final static PropertyChangeHandler propertyChangeListener = new PropertyChangeHandler();
    protected Icon smallIcon;
    private boolean defaults_initialized = false;
    /* These Dimensions/Rectangles are allocated once for all
     * RadioButtonUI.paint() calls.  Re-using rectangles
     * rather than allocating them in each paint call substantially
     * reduced the time it took paint to run.  Obviously, this
     * method can't be re-entered.
     */
    private static Dimension size = new Dimension();
    private static Rectangle viewR = new Rectangle();
    private static Rectangle iconR = new Rectangle();
    private static Rectangle textR = new Rectangle();
    private static Insets viewInsets = new Insets(0, 0, 0, 0);
    /**
     * Preferred spacing between radio buttons and other components.
     */
    private final static Insets regularSpacing = new Insets(6, 6, 6, 6);
    private final static Insets smallSpacing = new Insets(6, 6, 6, 6);
    private final static Insets miniSpacing = new Insets(5, 5, 5, 5);

    public static ComponentUI createUI(JComponent b) {
        return checkboxUI;
    }
    // ********************************
    //        Install PLAF
    // ********************************

    @Override
    protected void installDefaults(AbstractButton b) {
        super.installDefaults(b);
        if (!defaults_initialized) {
            smallIcon = UIManager.getIcon(getPropertyPrefix() + "smallIcon");
            defaults_initialized = true;
        }
        QuaquaUtilities.installProperty(b, "opaque", UIManager.get("RadioButton.opaque"));
        //b.setOpaque(false);
        b.setRequestFocusEnabled(UIManager.getBoolean("RadioButton.requestFocusEnabled"));
        b.setFocusable(UIManager.getBoolean("RadioButton.focusable"));
        updateFocusableState(b);
    }

    // ********************************
    //        Uninstall PLAF
    // ********************************
    @Override
    protected void uninstallDefaults(AbstractButton b) {
        super.uninstallDefaults(b);
        defaults_initialized = false;
    }

    @Override
    protected void installListeners(AbstractButton b) {
        super.installListeners(b);
        b.addPropertyChangeListener(propertyChangeListener);
        b.addItemListener(propertyChangeListener);
    }

    @Override
    protected void uninstallListeners(AbstractButton b) {
        super.uninstallListeners(b);
        b.removePropertyChangeListener(propertyChangeListener);
        b.removeItemListener(propertyChangeListener);
    }

    public Icon getDefaultIcon(JComponent c) {
        return (c.getFont().getSize() <= 11) ? smallIcon : icon;
    }

    @Override
    protected BasicButtonListener createButtonListener(AbstractButton b) {
        return new QuaquaButtonListener(b);
    }

    @Override
    public void paint(Graphics g, JComponent c) {
        Object oldHints = QuaquaUtilities.beginGraphics((Graphics2D) g);
        AbstractButton b = (AbstractButton) c;
        ButtonModel model = b.getModel();

        Font f = c.getFont();
        g.setFont(f);
        FontMetrics fm = g.getFontMetrics();

        Insets i = getInsets(b, viewInsets);
        size = b.getSize(size);
        viewR.x = i.left;
        viewR.y = i.top;
        viewR.width = size.width - (i.right + viewR.x);
        viewR.height = size.height - (i.bottom + viewR.y);
        iconR.x = iconR.y = iconR.width = iconR.height = 0;
        textR.x = textR.y = textR.width = textR.height = 0;

        Icon altIcon = b.getIcon();
        Icon selectedIcon = null;
        Icon disabledIcon = null;

        String text = layoutCL(
                b, fm, b.getText(), altIcon != null ? altIcon : getDefaultIcon(c),
                viewR, iconR, textR);
        // fill background
        if (c.isOpaque()) {
            g.setColor(b.getBackground());
            g.fillRect(0, 0, size.width, size.height);
        }

        // Paint the radio button
        if (altIcon != null) {

            if (!model.isEnabled()) {
                if (model.isSelected()) {
                    altIcon = b.getDisabledSelectedIcon();
                } else {
                    altIcon = b.getDisabledIcon();
                }
            } else if (model.isPressed() && model.isArmed()) {
                altIcon = b.getPressedIcon();
                if (altIcon == null) {
                    // Use selected icon
                    altIcon = b.getSelectedIcon();
                }
            } else if (model.isSelected()) {
                if (b.isRolloverEnabled() && model.isRollover()) {
                    altIcon = (Icon) b.getRolloverSelectedIcon();
                    if (altIcon == null) {
                        altIcon = (Icon) b.getSelectedIcon();
                    }
                } else {
                    altIcon = (Icon) b.getSelectedIcon();
                }
            } else if (b.isRolloverEnabled() && model.isRollover()) {
                altIcon = (Icon) b.getRolloverIcon();
            }

            if (altIcon == null) {
                altIcon = b.getIcon();
            }

            altIcon.paintIcon(c, g, iconR.x, iconR.y);

        } else {
            Icon defaultIcon = getDefaultIcon(c);
            if (defaultIcon != null) {
                // Visually adjust the vertical position of the icon, if the
                // "Small" style is used.
                if (f.getSize() <= 11) {
                    iconR.y -= 1;
                }
                defaultIcon.paintIcon(c, g, iconR.x, iconR.y);
            }
        }


        // Draw the Text
        if (text != null) {
            View v = (View) c.getClientProperty(BasicHTML.propertyKey);
            if (v != null) {
                v.paint(g, textR);
            } else {
                paintText(g, b, textR, text);
                if (b.hasFocus() && b.isFocusPainted()
                        && textR.width > 0 && textR.height > 0) {
                    paintFocus(g, textR, size);
                }
            }
        }

        QuaquaUtilities.endGraphics((Graphics2D) g, oldHints);
        Debug.paint(g, c, this);
    }

    @Override
    protected void paintFocus(Graphics g, Rectangle textR, Dimension size) {
    }

    /**
     * The preferred size of the radio button
     */
    @Override
    public Dimension getPreferredSize(JComponent c) {
        if (c.getComponentCount() > 0) {
            return null;
        }

        AbstractButton b = (AbstractButton) c;

        String text = b.getText();

        Icon buttonIcon = (Icon) b.getIcon();
        if (buttonIcon == null) {
            buttonIcon = getDefaultIcon(c);
        }

        Font font = b.getFont();
        FontMetrics fm = c.getFontMetrics(font);

        viewR.x = viewR.y = 0;
        viewR.width = Short.MAX_VALUE;
        viewR.height = Short.MAX_VALUE;
        iconR.x = iconR.y = iconR.width = iconR.height = 0;
        textR.x = textR.y = textR.width = textR.height = 0;

        layoutCL(
                b, fm, text, buttonIcon,
                viewR, iconR, textR);

        // find the union of the icon and text rects (from Rectangle.java)
        int x1 = Math.min(iconR.x, textR.x);
        int x2 = Math.max(iconR.x + iconR.width,
                textR.x + textR.width);
        int y1 = Math.min(iconR.y, textR.y);
        int y2 = Math.max(iconR.y + iconR.height,
                textR.y + textR.height);
        int width = x2 - x1;
        int height = y2 - y1;

        viewInsets = getInsets(b, viewInsets);

        width += viewInsets.left + viewInsets.right;
        height += viewInsets.top + viewInsets.bottom;

        return new Dimension(width, height);
    }

    /**
     * Workaround for Matisse GUI builder.
     */
    private Insets getInsets(AbstractButton b, Insets i) {
        i = b.getInsets(i);
        if (UIManager.getBoolean("RadioButton.enforceVisualMargin")) {
            Insets vmargin = UIManager.getInsets("Component.visualMargin");
            i.left = Math.max(i.left, vmargin.left);
            i.top = Math.max(i.top, vmargin.top);
            i.bottom = Math.max(i.bottom, vmargin.bottom);
            i.right = Math.max(i.right, vmargin.right);
        }
        return i;
    }

    /**
     * Method which renders the text of the current button.
     * 

* @param g Graphics context * @param b Current button to render * @param textR Bounding rectangle to render the text. * @param text String to render * @since 1.4 */ @Override protected void paintText(Graphics g, AbstractButton b, Rectangle textR, String text) { ButtonModel model = b.getModel(); FontMetrics fm = g.getFontMetrics(); int mnemonicIndex = Methods.invokeGetter(b, "getDisplayedMnemonicIndex", -1); /* Draw the Text */ if (model.isEnabled()) { /*** paint the text normally */ g.setColor(b.getForeground()); } else { Color c = UIManager.getColor("RadioButton.disabledForeground"); g.setColor((c != null) ? c : b.getForeground()); } QuaquaUtilities.drawStringUnderlineCharAt(g, text, mnemonicIndex, textR.x + getTextShiftOffset(), textR.y + fm.getAscent() + getTextShiftOffset()); } /** * This inner class is marked "public" due to a compiler bug. * This class should be treated as a "protected" inner class. * Instantiate it only within subclasses of BasicTabbedPaneUI. */ public static class PropertyChangeHandler implements PropertyChangeListener, ItemListener { public void propertyChange(PropertyChangeEvent evt) { String name = evt.getPropertyName(); AbstractButton src = (AbstractButton) evt.getSource(); if (name.equals("Frame.active") && src.isSelected()) { src.repaint(); } else if (name.equals("JComponent.sizeVariant")) { QuaquaUtilities.applySizeVariant(src); } } public void itemStateChanged(ItemEvent evt) { AbstractButton src = (AbstractButton) evt.getSource(); updateFocusableState(src); } } /** * Forwards the call to SwingUtilities.layoutCompoundLabel(). * This method is here so that a subclass could do Label specific * layout and to shorten the method name a little. * * @see SwingUtilities#layoutCompoundLabel */ protected String layoutCL( AbstractButton c, FontMetrics fontMetrics, String text, Icon icon, Rectangle viewR, Rectangle iconR, Rectangle textR) { String clippedText = SwingUtilities.layoutCompoundLabel( c, fontMetrics, text, icon, c.getVerticalAlignment(), c.getHorizontalAlignment(), c.getVerticalTextPosition(), c.getHorizontalTextPosition(), viewR, iconR, textR, Methods.invokeGetter(c, "getIconTextGap", 4)); if (fontMetrics.getHeight() >= 13) { iconR.y -= 1; // Shift the icon up by one pixel } return clippedText; } @Override public int getBaseline(JComponent c, int width, int height) { Rectangle vb = getVisualBounds(c, VisuallyLayoutable.TEXT_BOUNDS, width, height); return (vb == null) ? -1 : vb.y + vb.height; } public Rectangle getVisualBounds(JComponent c, int type, int width, int height) { Rectangle rect = new Rectangle(0, 0, width, height); if (type == VisuallyLayoutable.CLIP_BOUNDS) { return rect; } AbstractButton b = (AbstractButton) c; String text = b.getText(); Icon icon = (b.isEnabled()) ? b.getIcon() : b.getDisabledIcon(); if (icon == null) { icon = getDefaultIcon(b); } if ((icon == null) && (text == null)) { return rect; } FontMetrics fm = c.getFontMetrics(c.getFont()); Insets insets = getInsets(b, viewInsets); viewR.x = insets.left; viewR.y = insets.top; viewR.width = width - (insets.left + insets.right); viewR.height = height - (insets.top + insets.bottom); iconR.x = iconR.y = iconR.width = iconR.height = 0; textR.x = textR.y = textR.width = textR.height = 0; String clippedText = layoutCL(b, fm, text, icon, viewR, iconR, textR); Rectangle textBounds = Fonts.getPerceivedBounds(text, c.getFont(), c); int ascent = fm.getAscent(); textR.x += textBounds.x; textR.width = textBounds.width; textR.y += ascent + textBounds.y; textR.height = textBounds.height; // Determine rect rectangle switch (type) { case VisuallyLayoutable.COMPONENT_BOUNDS: rect = textR.union(iconR); break; case VisuallyLayoutable.TEXT_BOUNDS: rect.setBounds(textR); break; } return rect; } public static void updateFocusableState(AbstractButton button) { if (UIManager.getBoolean("Button.focusable") && !UIManager.getBoolean("Button.requestFocusEnabled")) { ButtonModel model = button.getModel(); if (model instanceof DefaultButtonModel) { /*ButtonGroup grp = ((DefaultButtonModel) model).getGroup(); if (grp != null) { for (Enumeration i=grp.getElements();i.hasMoreElements();){ AbstractButton btn=i.nextElement(); btn.setFocusable(btn.isSelected()); } }*/ button.setFocusable(button.isSelected()); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy