1/*
2 * Copyright (c) 2003, 2014, 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 javax.swing.plaf.metal;
27
28import java.awt.*;
29import java.net.URL;
30import java.util.*;
31import javax.swing.*;
32import javax.swing.plaf.*;
33import sun.swing.SwingUtilities2;
34import sun.swing.PrintColorUIResource;
35
36/**
37 * The default theme for the {@code MetalLookAndFeel}.
38 * <p>
39 * The designers
40 * of the Metal Look and Feel strive to keep the default look up to
41 * date, possibly through the use of new themes in the future.
42 * Therefore, developers should only use this class directly when they
43 * wish to customize the "Ocean" look, or force it to be the current
44 * theme, regardless of future updates.
45
46 * <p>
47 * All colors returned by {@code OceanTheme} are completely
48 * opaque.
49 *
50 * @since 1.5
51 * @see MetalLookAndFeel#setCurrentTheme
52 */
53@SuppressWarnings("serial") // Superclass is not serializable across versions
54public class OceanTheme extends DefaultMetalTheme {
55    private static final ColorUIResource PRIMARY1 =
56                              new ColorUIResource(0x6382BF);
57    private static final ColorUIResource PRIMARY2 =
58                              new ColorUIResource(0xA3B8CC);
59    private static final ColorUIResource PRIMARY3 =
60                              new ColorUIResource(0xB8CFE5);
61    private static final ColorUIResource SECONDARY1 =
62                              new ColorUIResource(0x7A8A99);
63    private static final ColorUIResource SECONDARY2 =
64                              new ColorUIResource(0xB8CFE5);
65    private static final ColorUIResource SECONDARY3 =
66                              new ColorUIResource(0xEEEEEE);
67
68    private static final ColorUIResource CONTROL_TEXT_COLOR =
69                              new PrintColorUIResource(0x333333, Color.BLACK);
70    private static final ColorUIResource INACTIVE_CONTROL_TEXT_COLOR =
71                              new ColorUIResource(0x999999);
72    private static final ColorUIResource MENU_DISABLED_FOREGROUND =
73                              new ColorUIResource(0x999999);
74    private static final ColorUIResource OCEAN_BLACK =
75                              new PrintColorUIResource(0x333333, Color.BLACK);
76
77    private static final ColorUIResource OCEAN_DROP =
78                              new ColorUIResource(0xD2E9FF);
79
80    // ComponentOrientation Icon
81    // Delegates to different icons based on component orientation
82    private static class COIcon extends IconUIResource {
83        private Icon rtl;
84
85        public COIcon(Icon ltr, Icon rtl) {
86            super(ltr);
87            this.rtl = rtl;
88        }
89
90        public void paintIcon(Component c, Graphics g, int x, int y) {
91            if (MetalUtils.isLeftToRight(c)) {
92                super.paintIcon(c, g, x, y);
93            } else {
94                rtl.paintIcon(c, g, x, y);
95            }
96        }
97    }
98
99    // InternalFrame Icon
100    // Delegates to different icons based on button state
101    @SuppressWarnings("serial") // Superclass is not serializable across versions
102    private static class IFIcon extends IconUIResource {
103        private Icon pressed;
104
105        public IFIcon(Icon normal, Icon pressed) {
106            super(normal);
107            this.pressed = pressed;
108        }
109
110        public void paintIcon(Component c, Graphics g, int x, int y) {
111            ButtonModel model = ((AbstractButton)c).getModel();
112            if (model.isPressed() && model.isArmed()) {
113                pressed.paintIcon(c, g, x, y);
114            } else {
115                super.paintIcon(c, g, x, y);
116            }
117        }
118    }
119
120    /**
121     * Creates an instance of <code>OceanTheme</code>
122     */
123    public OceanTheme() {
124    }
125
126    /**
127     * Add this theme's custom entries to the defaults table.
128     *
129     * @param table the defaults table, non-null
130     * @throws NullPointerException if {@code table} is {@code null}
131     */
132    public void addCustomEntriesToTable(UIDefaults table) {
133        UIDefaults.LazyValue focusBorder = t ->
134            new BorderUIResource.LineBorderUIResource(getPrimary1());
135        // .30 0 DDE8F3 white secondary2
136        java.util.List<?> buttonGradient = Arrays.asList(
137                 new Object[] {Float.valueOf(.3f), Float.valueOf(0f),
138                 new ColorUIResource(0xDDE8F3), getWhite(), getSecondary2() });
139
140        // Other possible properties that aren't defined:
141        //
142        // Used when generating the disabled Icons, provides the region to
143        // constrain grays to.
144        // Button.disabledGrayRange -> Object[] of Integers giving min/max
145        // InternalFrame.inactiveTitleGradient -> Gradient when the
146        //   internal frame is inactive.
147        Color cccccc = new ColorUIResource(0xCCCCCC);
148        Color dadada = new ColorUIResource(0xDADADA);
149        Color c8ddf2 = new ColorUIResource(0xC8DDF2);
150        Object directoryIcon = getIconResource("icons/ocean/directory.gif");
151        Object fileIcon = getIconResource("icons/ocean/file.gif");
152        java.util.List<?> sliderGradient = Arrays.asList(new Object[] {
153            Float.valueOf(.3f), Float.valueOf(.2f),
154            c8ddf2, getWhite(), new ColorUIResource(SECONDARY2) });
155
156        Object[] defaults = new Object[] {
157            "Button.gradient", buttonGradient,
158            "Button.rollover", Boolean.TRUE,
159            "Button.toolBarBorderBackground", INACTIVE_CONTROL_TEXT_COLOR,
160            "Button.disabledToolBarBorderBackground", cccccc,
161            "Button.rolloverIconType", "ocean",
162
163            "CheckBox.rollover", Boolean.TRUE,
164            "CheckBox.gradient", buttonGradient,
165
166            "CheckBoxMenuItem.gradient", buttonGradient,
167
168            // home2
169            "FileChooser.homeFolderIcon",
170                 getIconResource("icons/ocean/homeFolder.gif"),
171            // directory2
172            "FileChooser.newFolderIcon",
173                 getIconResource("icons/ocean/newFolder.gif"),
174            // updir2
175            "FileChooser.upFolderIcon",
176                 getIconResource("icons/ocean/upFolder.gif"),
177
178            // computer2
179            "FileView.computerIcon",
180                 getIconResource("icons/ocean/computer.gif"),
181            "FileView.directoryIcon", directoryIcon,
182            // disk2
183            "FileView.hardDriveIcon",
184                 getIconResource("icons/ocean/hardDrive.gif"),
185            "FileView.fileIcon", fileIcon,
186            // floppy2
187            "FileView.floppyDriveIcon",
188                 getIconResource("icons/ocean/floppy.gif"),
189
190            "Label.disabledForeground", getInactiveControlTextColor(),
191
192            "Menu.opaque", Boolean.FALSE,
193
194            "MenuBar.gradient", Arrays.asList(new Object[] {
195                     Float.valueOf(1f), Float.valueOf(0f),
196                     getWhite(), dadada,
197                     new ColorUIResource(dadada) }),
198            "MenuBar.borderColor", cccccc,
199
200            "InternalFrame.activeTitleGradient", buttonGradient,
201            // close2
202            "InternalFrame.closeIcon",
203                     new UIDefaults.LazyValue() {
204                         public Object createValue(UIDefaults table) {
205                             return new IFIcon(getHastenedIcon("icons/ocean/close.gif", table),
206                                               getHastenedIcon("icons/ocean/close-pressed.gif", table));
207                         }
208                     },
209            // minimize
210            "InternalFrame.iconifyIcon",
211                     new UIDefaults.LazyValue() {
212                         public Object createValue(UIDefaults table) {
213                             return new IFIcon(getHastenedIcon("icons/ocean/iconify.gif", table),
214                                               getHastenedIcon("icons/ocean/iconify-pressed.gif", table));
215                         }
216                     },
217            // restore
218            "InternalFrame.minimizeIcon",
219                     new UIDefaults.LazyValue() {
220                         public Object createValue(UIDefaults table) {
221                             return new IFIcon(getHastenedIcon("icons/ocean/minimize.gif", table),
222                                               getHastenedIcon("icons/ocean/minimize-pressed.gif", table));
223                         }
224                     },
225            // menubutton3
226            "InternalFrame.icon",
227                     getIconResource("icons/ocean/menu.gif"),
228            // maximize2
229            "InternalFrame.maximizeIcon",
230                     new UIDefaults.LazyValue() {
231                         public Object createValue(UIDefaults table) {
232                             return new IFIcon(getHastenedIcon("icons/ocean/maximize.gif", table),
233                                               getHastenedIcon("icons/ocean/maximize-pressed.gif", table));
234                         }
235                     },
236            // paletteclose
237            "InternalFrame.paletteCloseIcon",
238                     new UIDefaults.LazyValue() {
239                         public Object createValue(UIDefaults table) {
240                             return new IFIcon(getHastenedIcon("icons/ocean/paletteClose.gif", table),
241                                               getHastenedIcon("icons/ocean/paletteClose-pressed.gif", table));
242                         }
243                     },
244
245            "List.focusCellHighlightBorder", focusBorder,
246
247            "MenuBarUI", "javax.swing.plaf.metal.MetalMenuBarUI",
248
249            "OptionPane.errorIcon",
250                   getIconResource("icons/ocean/error.png"),
251            "OptionPane.informationIcon",
252                   getIconResource("icons/ocean/info.png"),
253            "OptionPane.questionIcon",
254                   getIconResource("icons/ocean/question.png"),
255            "OptionPane.warningIcon",
256                   getIconResource("icons/ocean/warning.png"),
257
258            "RadioButton.gradient", buttonGradient,
259            "RadioButton.rollover", Boolean.TRUE,
260
261            "RadioButtonMenuItem.gradient", buttonGradient,
262
263            "ScrollBar.gradient", buttonGradient,
264
265            "Slider.altTrackColor", new ColorUIResource(0xD2E2EF),
266            "Slider.gradient", sliderGradient,
267            "Slider.focusGradient", sliderGradient,
268
269            "SplitPane.oneTouchButtonsOpaque", Boolean.FALSE,
270            "SplitPane.dividerFocusColor", c8ddf2,
271
272            "TabbedPane.borderHightlightColor", getPrimary1(),
273            "TabbedPane.contentAreaColor", c8ddf2,
274            "TabbedPane.contentBorderInsets", new Insets(4, 2, 3, 3),
275            "TabbedPane.selected", c8ddf2,
276            "TabbedPane.tabAreaBackground", dadada,
277            "TabbedPane.tabAreaInsets", new Insets(2, 2, 0, 6),
278            "TabbedPane.unselectedBackground", SECONDARY3,
279
280            "Table.focusCellHighlightBorder", focusBorder,
281            "Table.gridColor", SECONDARY1,
282            "TableHeader.focusCellBackground", c8ddf2,
283
284            "ToggleButton.gradient", buttonGradient,
285
286            "ToolBar.borderColor", cccccc,
287            "ToolBar.isRollover", Boolean.TRUE,
288
289            "Tree.closedIcon", directoryIcon,
290
291            "Tree.collapsedIcon",
292                  new UIDefaults.LazyValue() {
293                      public Object createValue(UIDefaults table) {
294                          return new COIcon(getHastenedIcon("icons/ocean/collapsed.gif", table),
295                                            getHastenedIcon("icons/ocean/collapsed-rtl.gif", table));
296                      }
297                  },
298
299            "Tree.expandedIcon",
300                  getIconResource("icons/ocean/expanded.gif"),
301            "Tree.leafIcon", fileIcon,
302            "Tree.openIcon", directoryIcon,
303            "Tree.selectionBorderColor", getPrimary1(),
304            "Tree.dropLineColor", getPrimary1(),
305            "Table.dropLineColor", getPrimary1(),
306            "Table.dropLineShortColor", OCEAN_BLACK,
307
308            "Table.dropCellBackground", OCEAN_DROP,
309            "Tree.dropCellBackground", OCEAN_DROP,
310            "List.dropCellBackground", OCEAN_DROP,
311            "List.dropLineColor", getPrimary1()
312        };
313        table.putDefaults(defaults);
314    }
315
316    /**
317     * Overriden to enable picking up the system fonts, if applicable.
318     */
319    boolean isSystemTheme() {
320        return true;
321    }
322
323    /**
324     * Return the name of this theme, "Ocean".
325     *
326     * @return "Ocean"
327     */
328    public String getName() {
329        return "Ocean";
330    }
331
332    /**
333     * Returns the primary 1 color. This returns a color with an rgb hex value
334     * of {@code 0x6382BF}.
335     *
336     * @return the primary 1 color
337     * @see java.awt.Color#decode
338     */
339    protected ColorUIResource getPrimary1() {
340        return PRIMARY1;
341    }
342
343    /**
344     * Returns the primary 2 color. This returns a color with an rgb hex value
345     * of {@code 0xA3B8CC}.
346     *
347     * @return the primary 2 color
348     * @see java.awt.Color#decode
349     */
350    protected ColorUIResource getPrimary2() {
351        return PRIMARY2;
352    }
353
354    /**
355     * Returns the primary 3 color. This returns a color with an rgb hex value
356     * of {@code 0xB8CFE5}.
357     *
358     * @return the primary 3 color
359     * @see java.awt.Color#decode
360     */
361    protected ColorUIResource getPrimary3() {
362        return PRIMARY3;
363    }
364
365    /**
366     * Returns the secondary 1 color. This returns a color with an rgb hex
367     * value of {@code 0x7A8A99}.
368     *
369     * @return the secondary 1 color
370     * @see java.awt.Color#decode
371     */
372    protected ColorUIResource getSecondary1() {
373        return SECONDARY1;
374    }
375
376    /**
377     * Returns the secondary 2 color. This returns a color with an rgb hex
378     * value of {@code 0xB8CFE5}.
379     *
380     * @return the secondary 2 color
381     * @see java.awt.Color#decode
382     */
383    protected ColorUIResource getSecondary2() {
384        return SECONDARY2;
385    }
386
387    /**
388     * Returns the secondary 3 color. This returns a color with an rgb hex
389     * value of {@code 0xEEEEEE}.
390     *
391     * @return the secondary 3 color
392     * @see java.awt.Color#decode
393     */
394    protected ColorUIResource getSecondary3() {
395        return SECONDARY3;
396    }
397
398    /**
399     * Returns the black color. This returns a color with an rgb hex
400     * value of {@code 0x333333}.
401     *
402     * @return the black color
403     * @see java.awt.Color#decode
404     */
405    protected ColorUIResource getBlack() {
406        return OCEAN_BLACK;
407    }
408
409    /**
410     * Returns the desktop color. This returns a color with an rgb hex
411     * value of {@code 0xFFFFFF}.
412     *
413     * @return the desktop color
414     * @see java.awt.Color#decode
415     */
416    public ColorUIResource getDesktopColor() {
417        return MetalTheme.white;
418    }
419
420    /**
421     * Returns the inactive control text color. This returns a color with an
422     * rgb hex value of {@code 0x999999}.
423     *
424     * @return the inactive control text color
425     */
426    public ColorUIResource getInactiveControlTextColor() {
427        return INACTIVE_CONTROL_TEXT_COLOR;
428    }
429
430    /**
431     * Returns the control text color. This returns a color with an
432     * rgb hex value of {@code 0x333333}.
433     *
434     * @return the control text color
435     */
436    public ColorUIResource getControlTextColor() {
437        return CONTROL_TEXT_COLOR;
438    }
439
440    /**
441     * Returns the menu disabled foreground color. This returns a color with an
442     * rgb hex value of {@code 0x999999}.
443     *
444     * @return the menu disabled foreground color
445     */
446    public ColorUIResource getMenuDisabledForeground() {
447        return MENU_DISABLED_FOREGROUND;
448    }
449
450    private Object getIconResource(String iconID) {
451        return SwingUtilities2.makeIcon(getClass(), OceanTheme.class, iconID);
452    }
453
454    // makes use of getIconResource() to fetch an icon and then hastens it
455    // - calls createValue() on it and returns the actual icon
456    private Icon getHastenedIcon(String iconID, UIDefaults table) {
457        Object res = getIconResource(iconID);
458        return (Icon)((UIDefaults.LazyValue)res).createValue(table);
459    }
460}
461