1/*
2 * Copyright (c) 2000, 2015, 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
26package com.sun.java.swing.plaf.windows;
27
28import sun.swing.SwingUtilities2;
29
30import java.awt.*;
31
32import javax.swing.*;
33import javax.swing.plaf.UIResource;
34
35import static com.sun.java.swing.plaf.windows.TMSchema.*;
36
37/**
38 * A collection of static utility methods used for rendering the Windows look
39 * and feel.
40 *
41 * @author Mark Davidson
42 * @since 1.4
43 */
44public class WindowsGraphicsUtils {
45
46    /**
47     * Renders a text String in Windows without the mnemonic.
48     * This is here because the WindowsUI hierarchy doesn't match the Component hierarchy. All
49     * the overriden paintText methods of the ButtonUI delegates will call this static method.
50     *
51     * @param g Graphics context
52     * @param b Current button to render
53     * @param textRect Bounding rectangle to render the text.
54     * @param text String to render
55     */
56    public static void paintText(Graphics g, AbstractButton b,
57                                        Rectangle textRect, String text,
58                                        int textShiftOffset) {
59        FontMetrics fm = SwingUtilities2.getFontMetrics(b, g);
60
61        int mnemIndex = b.getDisplayedMnemonicIndex();
62        // W2K Feature: Check to see if the Underscore should be rendered.
63        if (WindowsLookAndFeel.isMnemonicHidden() == true) {
64            mnemIndex = -1;
65        }
66
67        XPStyle xp = XPStyle.getXP();
68        if (xp != null && !(b instanceof JMenuItem)) {
69            paintXPText(b, g, textRect.x + textShiftOffset,
70                    textRect.y + fm.getAscent() + textShiftOffset,
71                    text, mnemIndex);
72        } else {
73            paintClassicText(b, g, textRect.x + textShiftOffset,
74                    textRect.y + fm.getAscent() + textShiftOffset,
75                    text, mnemIndex);
76        }
77    }
78
79    static void paintClassicText(AbstractButton b, Graphics g, int x, int y,
80                                 String text, int mnemIndex) {
81        ButtonModel model = b.getModel();
82
83        /* Draw the Text */
84        Color color = b.getForeground();
85        if(model.isEnabled()) {
86            /*** paint the text normally */
87            if(!(b instanceof JMenuItem && model.isArmed())
88                && !(b instanceof JMenu && (model.isSelected() || model.isRollover()))) {
89                /* We shall not set foreground color for selected menu or
90                 * armed menuitem. Foreground must be set in appropriate
91                 * Windows* class because these colors passes from
92                 * BasicMenuItemUI as protected fields and we can't
93                 * reach them from this class */
94                g.setColor(b.getForeground());
95            }
96            SwingUtilities2.drawStringUnderlineCharAt(b, g,text, mnemIndex, x, y);
97        } else {        /*** paint the text disabled ***/
98            color = getDisabledTextColor(b);
99            if (color == null) {
100                color = UIManager.getColor("Button.shadow");
101            }
102            Color shadow = UIManager.getColor("Button.disabledShadow");
103            if(model.isArmed()) {
104                color = UIManager.getColor("Button.disabledForeground");
105            } else {
106                if (shadow == null) {
107                    shadow = b.getBackground().darker();
108                }
109                g.setColor(shadow);
110                SwingUtilities2.drawStringUnderlineCharAt(b, g, text, mnemIndex,
111                                                          x + 1, y + 1);
112            }
113            if (color == null) {
114                color = b.getBackground().brighter();
115            }
116            g.setColor(color);
117            SwingUtilities2.drawStringUnderlineCharAt(b, g, text, mnemIndex, x, y);
118        }
119    }
120
121    private static Color getDisabledTextColor(AbstractButton b) {
122        if (b instanceof JCheckBox) {
123            return UIManager.getColor("CheckBox.disabledText");
124        } else if (b instanceof JRadioButton) {
125            return UIManager.getColor("RadioButton.disabledText");
126        } else if (b instanceof JToggleButton) {
127            return  UIManager.getColor("ToggleButton.disabledText");
128        } else if (b instanceof JButton) {
129            return UIManager.getColor("Button.disabledText");
130        }
131        return null;
132    }
133
134    static void paintXPText(AbstractButton b, Graphics g, int x, int y,
135                            String text, int mnemIndex) {
136        Part part = WindowsButtonUI.getXPButtonType(b);
137        State state = WindowsButtonUI.getXPButtonState(b);
138        paintXPText(b, part, state, g, x, y, text, mnemIndex);
139    }
140
141    static void paintXPText(AbstractButton b, Part part, State state,
142            Graphics g, int x, int y, String text, int mnemIndex) {
143        XPStyle xp = XPStyle.getXP();
144        if (xp == null) {
145            return;
146        }
147        Color textColor;
148        if (b.isEnabled()) {
149            textColor = b.getForeground();
150        }
151        else {
152            textColor = getDisabledTextColor(b);
153        }
154
155        if (textColor == null || textColor instanceof UIResource) {
156            textColor = xp.getColor(b, part, state, Prop.TEXTCOLOR, b.getForeground());
157            // to work around an apparent bug in Windows, use the pushbutton
158            // color for disabled toolbar buttons if the disabled color is the
159            // same as the enabled color
160            if (part == Part.TP_BUTTON && state == State.DISABLED) {
161                Color enabledColor = xp.getColor(b, part, State.NORMAL,
162                                     Prop.TEXTCOLOR, b.getForeground());
163                if(textColor.equals(enabledColor)) {
164                    textColor = xp.getColor(b, Part.BP_PUSHBUTTON, state,
165                                Prop.TEXTCOLOR, textColor);
166                }
167            }
168            // only draw shadow if developer hasn't changed the foreground color
169            // and if the current style has text shadows.
170            TypeEnum shadowType = xp.getTypeEnum(b, part,
171                                                 state, Prop.TEXTSHADOWTYPE);
172            if (shadowType == TypeEnum.TST_SINGLE ||
173                        shadowType == TypeEnum.TST_CONTINUOUS) {
174                Color shadowColor = xp.getColor(b, part, state,
175                                                Prop.TEXTSHADOWCOLOR, Color.black);
176                Point offset = xp.getPoint(b, part, state, Prop.TEXTSHADOWOFFSET);
177                if (offset != null) {
178                    g.setColor(shadowColor);
179                    SwingUtilities2.drawStringUnderlineCharAt(b, g, text, mnemIndex,
180                                                              x + offset.x,
181                                                              y + offset.y);
182                }
183            }
184        }
185
186        g.setColor(textColor);
187        SwingUtilities2.drawStringUnderlineCharAt(b, g, text, mnemIndex, x, y);
188    }
189
190    static boolean isLeftToRight(Component c) {
191        return c.getComponentOrientation().isLeftToRight();
192    }
193
194    /*
195     * Repaints all the components with the mnemonics in the given window and
196     * all its owned windows.
197     */
198    static void repaintMnemonicsInWindow(Window w) {
199        if(w == null || !w.isShowing()) {
200            return;
201        }
202
203        Window[] ownedWindows = w.getOwnedWindows();
204        for(int i=0;i<ownedWindows.length;i++) {
205            repaintMnemonicsInWindow(ownedWindows[i]);
206        }
207
208        repaintMnemonicsInContainer(w);
209    }
210
211    /*
212     * Repaints all the components with the mnemonics in container.
213     * Recursively searches for all the subcomponents.
214     */
215    static void repaintMnemonicsInContainer(Container cont) {
216        Component c;
217        for(int i=0; i<cont.getComponentCount(); i++) {
218            c = cont.getComponent(i);
219            if(c == null || !c.isVisible()) {
220                continue;
221            }
222            if(c instanceof AbstractButton
223               && ((AbstractButton)c).getMnemonic() != '\0') {
224                c.repaint();
225                continue;
226            } else if(c instanceof JLabel
227                      && ((JLabel)c).getDisplayedMnemonic() != '\0') {
228                c.repaint();
229                continue;
230            }
231            if(c instanceof Container) {
232                repaintMnemonicsInContainer((Container)c);
233            }
234        }
235    }
236}
237