Path: blob/master/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonLabeledUI.java
41154 views
/*1* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.apple.laf;2627import java.awt.*;28import java.awt.image.BufferedImage;2930import javax.swing.*;31import javax.swing.border.Border;32import javax.swing.plaf.UIResource;33import javax.swing.plaf.basic.BasicHTML;34import javax.swing.text.View;3536import apple.laf.*;37import apple.laf.JRSUIConstants.*;38import apple.laf.JRSUIState.ValueState;3940import com.apple.laf.AquaUtilControlSize.*;41import com.apple.laf.AquaUtils.RecyclableSingleton;4243public abstract class AquaButtonLabeledUI extends AquaButtonToggleUI implements Sizeable {44private static final RecyclableSizingIcon regularIcon = new RecyclableSizingIcon(18);45private static final RecyclableSizingIcon smallIcon = new RecyclableSizingIcon(16);46private static final RecyclableSizingIcon miniIcon = new RecyclableSizingIcon(14);4748protected static class RecyclableSizingIcon extends RecyclableSingleton<Icon> {49final int iconSize;50public RecyclableSizingIcon(final int iconSize) { this.iconSize = iconSize; }5152protected Icon getInstance() {53return new ImageIcon(new BufferedImage(iconSize, iconSize, BufferedImage.TYPE_INT_ARGB_PRE));54}55}5657protected AquaButtonBorder widgetBorder;5859public AquaButtonLabeledUI() {60widgetBorder = getPainter();61}6263public void applySizeFor(final JComponent c, final Size newSize) {64super.applySizeFor(c, newSize);65widgetBorder = (AquaButtonBorder)widgetBorder.deriveBorderForSize(newSize);66}6768public Icon getDefaultIcon(final JComponent c) {69final Size componentSize = AquaUtilControlSize.getUserSizeFrom(c);70if (componentSize == Size.REGULAR) return regularIcon.get();71if (componentSize == Size.SMALL) return smallIcon.get();72if (componentSize == Size.MINI) return miniIcon.get();73return regularIcon.get();74}7576protected void setThemeBorder(final AbstractButton b) {77super.setThemeBorder(b);7879Border border = b.getBorder();80if (border == null || border instanceof UIResource) {81// Set the correct border82b.setBorder(AquaButtonBorder.getBevelButtonBorder());83}84}8586protected abstract AquaButtonBorder getPainter();8788public synchronized void paint(final Graphics g, final JComponent c) {89final AbstractButton b = (AbstractButton)c;90final ButtonModel model = b.getModel();9192final Font f = c.getFont();93g.setFont(f);94final FontMetrics fm = g.getFontMetrics();9596Dimension size = b.getSize();9798final Insets i = c.getInsets();99100Rectangle viewRect = new Rectangle(b.getWidth(), b.getHeight());101Rectangle iconRect = new Rectangle();102Rectangle textRect = new Rectangle();103104Icon altIcon = b.getIcon();105106final boolean isCellEditor = c.getParent() instanceof CellRendererPane;107108// This was erroneously removed to fix [3155996] but really we wanted the controls to just be109// opaque. So we put this back in to fix [3179839] (radio buttons not being translucent)110if (b.isOpaque() || isCellEditor) {111g.setColor(b.getBackground());112g.fillRect(0, 0, size.width, size.height);113}114115// only do this if borders are on!116if (((AbstractButton)c).isBorderPainted() && !isCellEditor) {117final Border border = c.getBorder();118if (border instanceof AquaButtonBorder) {119((AquaButtonBorder)border).paintButton(c, g, viewRect.x, viewRect.y, viewRect.width, viewRect.height);120}121}122123viewRect.x = i.left;124viewRect.y = i.top;125viewRect.width = b.getWidth() - (i.right + viewRect.x);126viewRect.height = b.getHeight() - (i.bottom + viewRect.y);127128// normal size ??129// at some point we substitute the small icon instead of the normal icon130// we should base this on height. Use normal unless we are under a certain size131// see our button code!132133final String text = SwingUtilities.layoutCompoundLabel(c, fm, b.getText(), altIcon != null ? altIcon : getDefaultIcon(b), b.getVerticalAlignment(), b.getHorizontalAlignment(), b.getVerticalTextPosition(), b.getHorizontalTextPosition(), viewRect, iconRect, textRect, b.getText() == null ? 0 : b.getIconTextGap());134135// fill background136137// draw the native radio button stuff here.138if (altIcon == null) {139widgetBorder.paintButton(c, g, iconRect.x, iconRect.y, iconRect.width, iconRect.height);140} else {141// Paint the button142if (!model.isEnabled()) {143if (model.isSelected()) {144altIcon = b.getDisabledSelectedIcon();145} else {146altIcon = b.getDisabledIcon();147}148} else if (model.isPressed() && model.isArmed()) {149altIcon = b.getPressedIcon();150if (altIcon == null) {151// Use selected icon152altIcon = b.getSelectedIcon();153}154} else if (model.isSelected()) {155if (b.isRolloverEnabled() && model.isRollover()) {156altIcon = b.getRolloverSelectedIcon();157if (altIcon == null) {158altIcon = b.getSelectedIcon();159}160} else {161altIcon = b.getSelectedIcon();162}163} else if (b.isRolloverEnabled() && model.isRollover()) {164altIcon = b.getRolloverIcon();165}166167if (altIcon == null) {168altIcon = b.getIcon();169}170171int offset = 0;172if (b.isFocusOwner()) {173offset = 2;174altIcon = AquaFocus.createFocusedIcon(altIcon, c, 2);175}176177altIcon.paintIcon(c, g, iconRect.x - offset, iconRect.y - offset);178}179180// Draw the Text181if (text != null) {182final View v = (View)c.getClientProperty(BasicHTML.propertyKey);183if (v != null) {184v.paint(g, textRect);185} else {186paintText(g, b, textRect, text);187}188}189}190191/**192* The preferred size of the button193*/194public Dimension getPreferredSize(final JComponent c) {195if (c.getComponentCount() > 0) { return null; }196197final AbstractButton b = (AbstractButton)c;198199final String text = b.getText();200201Icon buttonIcon = b.getIcon();202if (buttonIcon == null) {203buttonIcon = getDefaultIcon(b);204}205206final Font font = b.getFont();207final FontMetrics fm = b.getFontMetrics(font);208209Rectangle prefViewRect = new Rectangle(Short.MAX_VALUE, Short.MAX_VALUE);210Rectangle prefIconRect = new Rectangle();211Rectangle prefTextRect = new Rectangle();212213SwingUtilities.layoutCompoundLabel(c, fm, text, buttonIcon, b.getVerticalAlignment(), b.getHorizontalAlignment(), b.getVerticalTextPosition(), b.getHorizontalTextPosition(), prefViewRect, prefIconRect, prefTextRect, text == null ? 0 : b.getIconTextGap());214215// find the union of the icon and text rects (from Rectangle.java)216final int x1 = Math.min(prefIconRect.x, prefTextRect.x);217final int x2 = Math.max(prefIconRect.x + prefIconRect.width, prefTextRect.x + prefTextRect.width);218final int y1 = Math.min(prefIconRect.y, prefTextRect.y);219final int y2 = Math.max(prefIconRect.y + prefIconRect.height, prefTextRect.y + prefTextRect.height);220int width = x2 - x1;221int height = y2 - y1;222223Insets prefInsets = b.getInsets();224width += prefInsets.left + prefInsets.right;225height += prefInsets.top + prefInsets.bottom;226return new Dimension(width, height);227}228229public abstract static class LabeledButtonBorder extends AquaButtonBorder {230public LabeledButtonBorder(final SizeDescriptor sizeDescriptor) {231super(sizeDescriptor);232}233234public LabeledButtonBorder(final LabeledButtonBorder other) {235super(other);236}237238@Override239protected AquaPainter<? extends JRSUIState> createPainter() {240final AquaPainter<ValueState> painter = AquaPainter.create(JRSUIStateFactory.getLabeledButton());241painter.state.set(AlignmentVertical.CENTER);242painter.state.set(AlignmentHorizontal.CENTER);243return painter;244}245246protected void doButtonPaint(final AbstractButton b, final ButtonModel model, final Graphics g, final int x, final int y, final int width, final int height) {247painter.state.set(AquaUtilControlSize.getUserSizeFrom(b));248((ValueState)painter.state).setValue(model.isSelected() ? isIndeterminate(b) ? 2 : 1 : 0); // 2=mixed, 1=on, 0=off249super.doButtonPaint(b, model, g, x, y, width, height);250}251252protected State getButtonState(final AbstractButton b, final ButtonModel model) {253final State state = super.getButtonState(b, model);254255if (state == State.INACTIVE) return State.INACTIVE;256if (state == State.DISABLED) return State.DISABLED;257if (model.isArmed() && model.isPressed()) return State.PRESSED;258if (model.isSelected()) return State.ACTIVE;259260return state;261}262263static boolean isIndeterminate(final AbstractButton b) {264return "indeterminate".equals(b.getClientProperty("JButton.selectedState"));265}266}267}268269270