/* * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.java.swing.plaf.windows; import javax.swing.plaf.basic.*; import javax.swing.border.*; import javax.swing.plaf.*; import javax.swing.*; import java.awt.*; import static com.sun.java.swing.plaf.windows.TMSchema.*; import static com.sun.java.swing.plaf.windows.TMSchema.Part.*; import static com.sun.java.swing.plaf.windows.XPStyle.Skin; import sun.awt.AppContext; /** * Windows button. * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is appropriate * for short term storage or RMI between applications running the same * version of Swing. A future release of Swing will provide support for * long term persistence. * * @author Jeff Dinkins * */ public class WindowsButtonUI extends BasicButtonUI { protected int dashedRectGapX; protected int dashedRectGapY; protected int dashedRectGapWidth; protected int dashedRectGapHeight; protected Color focusColor; private boolean defaults_initialized = false; private static final Object WINDOWS_BUTTON_UI_KEY = new Object(); // ******************************** // Create PLAF // ******************************** public static ComponentUI createUI(JComponent c) { AppContext appContext = AppContext.getAppContext(); WindowsButtonUI windowsButtonUI = (WindowsButtonUI) appContext.get(WINDOWS_BUTTON_UI_KEY); if (windowsButtonUI == null) { windowsButtonUI = new WindowsButtonUI(); appContext.put(WINDOWS_BUTTON_UI_KEY, windowsButtonUI); } return windowsButtonUI; } // ******************************** // Defaults // ******************************** protected void installDefaults(AbstractButton b) { super.installDefaults(b); if(!defaults_initialized) { String pp = getPropertyPrefix(); dashedRectGapX = UIManager.getInt(pp + "dashedRectGapX"); dashedRectGapY = UIManager.getInt(pp + "dashedRectGapY"); dashedRectGapWidth = UIManager.getInt(pp + "dashedRectGapWidth"); dashedRectGapHeight = UIManager.getInt(pp + "dashedRectGapHeight"); focusColor = UIManager.getColor(pp + "focus"); defaults_initialized = true; } XPStyle xp = XPStyle.getXP(); if (xp != null) { b.setBorder(xp.getBorder(b, getXPButtonType(b))); LookAndFeel.installProperty(b, "rolloverEnabled", Boolean.TRUE); } } protected void uninstallDefaults(AbstractButton b) { super.uninstallDefaults(b); defaults_initialized = false; } protected Color getFocusColor() { return focusColor; } // ******************************** // Paint Methods // ******************************** /** * Overridden method to render the text without the mnemonic */ protected void paintText(Graphics g, AbstractButton b, Rectangle textRect, String text) { WindowsGraphicsUtils.paintText(g, b, textRect, text, getTextShiftOffset()); } protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, Rectangle textRect, Rectangle iconRect){ // focus painted same color as text on Basic?? int width = b.getWidth(); int height = b.getHeight(); g.setColor(getFocusColor()); BasicGraphicsUtils.drawDashedRect(g, dashedRectGapX, dashedRectGapY, width - dashedRectGapWidth, height - dashedRectGapHeight); } protected void paintButtonPressed(Graphics g, AbstractButton b){ setTextShiftOffset(); } // ******************************** // Layout Methods // ******************************** public Dimension getPreferredSize(JComponent c) { Dimension d = super.getPreferredSize(c); /* Ensure that the width and height of the button is odd, * to allow for the focus line if focus is painted */ AbstractButton b = (AbstractButton)c; if (d != null && b.isFocusPainted()) { if(d.width % 2 == 0) { d.width += 1; } if(d.height % 2 == 0) { d.height += 1; } } return d; } /* These rectangles/insets are allocated once for all * ButtonUI.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 Rectangle viewRect = new Rectangle(); public void paint(Graphics g, JComponent c) { if (XPStyle.getXP() != null) { WindowsButtonUI.paintXPButtonBackground(g, c); } super.paint(g, c); } static Part getXPButtonType(AbstractButton b) { if(b instanceof JCheckBox) { return Part.BP_CHECKBOX; } if(b instanceof JRadioButton) { return Part.BP_RADIOBUTTON; } boolean toolbar = (b.getParent() instanceof JToolBar); return toolbar ? Part.TP_BUTTON : Part.BP_PUSHBUTTON; } static State getXPButtonState(AbstractButton b) { Part part = getXPButtonType(b); ButtonModel model = b.getModel(); State state = State.NORMAL; switch (part) { case BP_RADIOBUTTON: /* falls through */ case BP_CHECKBOX: if (! model.isEnabled()) { state = (model.isSelected()) ? State.CHECKEDDISABLED : State.UNCHECKEDDISABLED; } else if (model.isPressed() && model.isArmed()) { state = (model.isSelected()) ? State.CHECKEDPRESSED : State.UNCHECKEDPRESSED; } else if (model.isRollover()) { state = (model.isSelected()) ? State.CHECKEDHOT : State.UNCHECKEDHOT; } else { state = (model.isSelected()) ? State.CHECKEDNORMAL : State.UNCHECKEDNORMAL; } break; case BP_PUSHBUTTON: /* falls through */ case TP_BUTTON: boolean toolbar = (b.getParent() instanceof JToolBar); if (toolbar) { if (model.isArmed() && model.isPressed()) { state = State.PRESSED; } else if (!model.isEnabled()) { state = State.DISABLED; } else if (model.isSelected() && model.isRollover()) { state = State.HOTCHECKED; } else if (model.isSelected()) { state = State.CHECKED; } else if (model.isRollover()) { state = State.HOT; } else if (b.hasFocus()) { state = State.HOT; } } else { if ((model.isArmed() && model.isPressed()) || model.isSelected()) { state = State.PRESSED; } else if (!model.isEnabled()) { state = State.DISABLED; } else if (model.isRollover() || model.isPressed()) { state = State.HOT; } else if (b instanceof JButton && ((JButton)b).isDefaultButton()) { state = State.DEFAULTED; } else if (b.hasFocus()) { state = State.HOT; } } break; default : state = State.NORMAL; } return state; } static void paintXPButtonBackground(Graphics g, JComponent c) { AbstractButton b = (AbstractButton)c; XPStyle xp = XPStyle.getXP(); Part part = getXPButtonType(b); if (b.isContentAreaFilled() && xp != null) { Skin skin = xp.getSkin(b, part); State state = getXPButtonState(b); Dimension d = c.getSize(); int dx = 0; int dy = 0; int dw = d.width; int dh = d.height; Border border = c.getBorder(); Insets insets; if (border != null) { // Note: The border may be compound, containing an outer // opaque border (supplied by the application), plus an // inner transparent margin border. We want to size the // background to fill the transparent part, but stay // inside the opaque part. insets = WindowsButtonUI.getOpaqueInsets(border, c); } else { insets = c.getInsets(); } if (insets != null) { dx += insets.left; dy += insets.top; dw -= (insets.left + insets.right); dh -= (insets.top + insets.bottom); } skin.paintSkin(g, dx, dy, dw, dh, state); } } /** * returns - b.getBorderInsets(c) if border is opaque * - null if border is completely non-opaque * - somewhere inbetween if border is compound and * outside border is opaque and inside isn't */ private static Insets getOpaqueInsets(Border b, Component c) { if (b == null) { return null; } if (b.isBorderOpaque()) { return b.getBorderInsets(c); } else if (b instanceof CompoundBorder) { CompoundBorder cb = (CompoundBorder)b; Insets iOut = getOpaqueInsets(cb.getOutsideBorder(), c); if (iOut != null && iOut.equals(cb.getOutsideBorder().getBorderInsets(c))) { // Outside border is opaque, keep looking Insets iIn = getOpaqueInsets(cb.getInsideBorder(), c); if (iIn == null) { // Inside is non-opaque, use outside insets return iOut; } else { // Found non-opaque somewhere in the inside (which is // also compound). return new Insets(iOut.top + iIn.top, iOut.left + iIn.left, iOut.bottom + iIn.bottom, iOut.right + iIn.right); } } else { // Outside is either all non-opaque or has non-opaque // border inside another compound border return iOut; } } else { return null; } } }