/* * Copyright (c) 2005-2016 Substance Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Substance Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.substance.internal.utils.icon; import java.awt.AlphaComposite; import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.geom.Ellipse2D; import java.awt.geom.GeneralPath; import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.Map; import javax.swing.Icon; import javax.swing.JSlider; import javax.swing.JTree; import javax.swing.plaf.UIResource; import org.pushingpixels.lafwidget.icon.HiDpiAwareIcon; import org.pushingpixels.lafwidget.icon.IsHiDpiAware; import org.pushingpixels.substance.api.ColorSchemeAssociationKind; import org.pushingpixels.substance.api.ComponentState; import org.pushingpixels.substance.api.SubstanceColorScheme; import org.pushingpixels.substance.api.painter.border.SubstanceBorderPainter; import org.pushingpixels.substance.api.painter.fill.SubstanceFillPainter; import org.pushingpixels.substance.internal.animation.StateTransitionTracker; import org.pushingpixels.substance.internal.animation.TransitionAwareUI; import org.pushingpixels.substance.internal.ui.SubstanceSliderUI; import org.pushingpixels.substance.internal.ui.SubstanceTreeUI; import org.pushingpixels.substance.internal.utils.HashMapKey; import org.pushingpixels.substance.internal.utils.LazyResettableHashMap; import org.pushingpixels.substance.internal.utils.SubstanceColorSchemeUtilities; import org.pushingpixels.substance.internal.utils.SubstanceCoreUtilities; import org.pushingpixels.substance.internal.utils.SubstanceImageCreator; import org.pushingpixels.substance.internal.utils.SubstanceOutlineUtilities; import org.pushingpixels.substance.internal.utils.SubstanceSizeUtils; /** * Icon factory for dynamically-changing icons. This class is <b>for internal * use only</b>. * * @author Kirill Grouchnikov */ public class SubstanceIconFactory { /** * Icons for horizontal slider in {@link SubstanceSliderUI}. */ private static LazyResettableHashMap<Icon> sliderHorizontalIcons = new LazyResettableHashMap<Icon>( "SubstanceIconFactory.sliderHorizontalIcon"); /** * Icons for horizontal slider in {@link SubstanceSliderUI}. */ private static LazyResettableHashMap<Icon> sliderRoundIcons = new LazyResettableHashMap<Icon>( "SubstanceIconFactory.sliderRoundIcon"); /** * Icons for vertical slider in {@link SubstanceSliderUI}. */ private static LazyResettableHashMap<Icon> sliderVerticalIcons = new LazyResettableHashMap<Icon>( "SubstanceIconFactory.sliderVerticalIcon"); /** * Icons for tree collapse / expand in {@link SubstanceTreeUI}. */ private static LazyResettableHashMap<Icon> treeIcons = new LazyResettableHashMap<Icon>( "SubstanceIconFactory.treeIcon"); /** * Retrieves icon for horizontal slider in {@link SubstanceSliderUI}. * * @param size * The size of the icon to retrieve. * @param isMirrorred * Indication whether the icon should be mirrored. * @return Icon for horizontal slider in {@link SubstanceSliderUI}. */ public static Icon getSliderHorizontalIcon(int size, boolean isMirrorred) { HashMapKey key = SubstanceCoreUtilities.getHashKey(size, isMirrorred); if (SubstanceIconFactory.sliderHorizontalIcons.get(key) == null) { Icon icon = new SliderHorizontalIcon(size, isMirrorred); SubstanceIconFactory.sliderHorizontalIcons.put(key, icon); } return SubstanceIconFactory.sliderHorizontalIcons.get(key); } /** * Retrieves round icon for slider in {@link SubstanceSliderUI}. * * @param size * The size of the icon to retrieve. * @return Round icon for slider in {@link SubstanceSliderUI}. */ public static Icon getSliderRoundIcon(int size) { HashMapKey key = SubstanceCoreUtilities.getHashKey(size); if (SubstanceIconFactory.sliderRoundIcons.get(key) == null) { Icon icon = new SliderRoundIcon(size); SubstanceIconFactory.sliderRoundIcons.put(key, icon); } return SubstanceIconFactory.sliderRoundIcons.get(key); } /** * Retrieves icon for vertical slider in {@link SubstanceSliderUI}. * * @param size * The size of the icon to retrieve. * @param isMirrorred * Indication whether the icon should be mirrored. * @return Icon for vertical slider in {@link SubstanceSliderUI}. */ public static Icon getSliderVerticalIcon(int size, boolean isMirrorred) { HashMapKey key = SubstanceCoreUtilities.getHashKey(size, isMirrorred); if (SubstanceIconFactory.sliderVerticalIcons.get(key) == null) { Icon icon = new SliderVerticalIcon(size, isMirrorred); SubstanceIconFactory.sliderVerticalIcons.put(key, icon); } return SubstanceIconFactory.sliderVerticalIcons.get(key); } public static Icon getTreeIcon(JTree tree, boolean isCollapsed) { int fontSize = SubstanceSizeUtils.getComponentFontSize(tree); int size = SubstanceSizeUtils.getTreeIconSize(fontSize); HashMapKey key = SubstanceCoreUtilities.getHashKey(size, isCollapsed); if (SubstanceIconFactory.treeIcons.get(key) == null) { Icon icon = new TreeIcon(size, isCollapsed); SubstanceIconFactory.treeIcons.put(key, icon); } return SubstanceIconFactory.treeIcons.get(key); } /** * Icon for horizontal slider in {@link SubstanceSliderUI}. * * @author Kirill Grouchnikov */ private static class SliderHorizontalIcon implements Icon, UIResource { /** * Icon hash. */ private static LazyResettableHashMap<HiDpiAwareIcon> icons = new LazyResettableHashMap<HiDpiAwareIcon>( "SubstanceIconFactory.SliderHorizontalIcon"); /** * The size of <code>this</code> icon. */ private int size; /** * Indication whether the icon is mirrorred. */ private boolean isMirrorred; /** * Simple constructor. * * @param size * The size of <code>this</code> icon. * @param isMirrorred * Indication whether the icon should be mirrored. */ public SliderHorizontalIcon(int size, boolean isMirrorred) { this.size = size; this.isMirrorred = isMirrorred; } private HiDpiAwareIcon getIcon(JSlider slider, StateTransitionTracker stateTransitionTracker) { StateTransitionTracker.ModelStateInfo modelStateInfo = stateTransitionTracker .getModelStateInfo(); Map<ComponentState, StateTransitionTracker.StateContributionInfo> activeStates = modelStateInfo .getStateContributionMap(); ComponentState currState = stateTransitionTracker.getModelStateInfo() .getCurrModelState(); float activeStrength = stateTransitionTracker.getActiveStrength(); float width = this.size * (2.0f + activeStrength) / 3.0f; SubstanceFillPainter fillPainter = SubstanceCoreUtilities.getFillPainter(slider); SubstanceBorderPainter borderPainter = SubstanceCoreUtilities.getBorderPainter(slider); SubstanceColorScheme baseFillScheme = SubstanceColorSchemeUtilities .getColorScheme(slider, currState); SubstanceColorScheme baseBorderScheme = SubstanceColorSchemeUtilities .getColorScheme(slider, ColorSchemeAssociationKind.BORDER, currState); HashMapKey baseKey = SubstanceCoreUtilities.getHashKey(this.size, width, baseFillScheme.getDisplayName(), baseBorderScheme.getDisplayName(), fillPainter.getDisplayName(), borderPainter.getDisplayName(), this.isMirrorred); HiDpiAwareIcon baseLayer = SliderHorizontalIcon.icons.get(baseKey); if (baseLayer == null) { baseLayer = getSingleLayer(slider, width, fillPainter, borderPainter, baseFillScheme, baseBorderScheme); SliderHorizontalIcon.icons.put(baseKey, baseLayer); } if (currState.isDisabled() || (activeStates.size() == 1)) return baseLayer; BufferedImage result = SubstanceCoreUtilities.getBlankImage(baseLayer.getIconWidth(), baseLayer.getIconHeight()); Graphics2D g2d = result.createGraphics(); baseLayer.paintIcon(slider, g2d, 0, 0); for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : activeStates .entrySet()) { ComponentState activeState = activeEntry.getKey(); if (activeState == currState) continue; float contribution = activeEntry.getValue().getContribution(); if (contribution == 0.0f) continue; SubstanceColorScheme fillScheme = SubstanceColorSchemeUtilities .getColorScheme(slider, activeState); SubstanceColorScheme borderScheme = SubstanceColorSchemeUtilities .getColorScheme(slider, ColorSchemeAssociationKind.BORDER, activeState); HashMapKey key = SubstanceCoreUtilities.getHashKey(this.size, width, fillScheme.getDisplayName(), borderScheme.getDisplayName(), fillPainter.getDisplayName(), borderPainter.getDisplayName(), this.isMirrorred); HiDpiAwareIcon layer = SliderHorizontalIcon.icons.get(key); if (layer == null) { layer = getSingleLayer(slider, width, fillPainter, borderPainter, fillScheme, borderScheme); SliderHorizontalIcon.icons.put(key, layer); } g2d.setComposite(AlphaComposite.SrcOver.derive(contribution)); layer.paintIcon(slider, g2d, 0, 0); } g2d.dispose(); return new HiDpiAwareIcon(result); } private HiDpiAwareIcon getSingleLayer(JSlider slider, float width, SubstanceFillPainter fillPainter, SubstanceBorderPainter borderPainter, SubstanceColorScheme fillScheme, SubstanceColorScheme borderScheme) { float borderDelta = SubstanceSizeUtils.getBorderStrokeWidth() / 2.0f; Shape contour = SubstanceOutlineUtilities.getTriangleButtonOutline(width, this.size - 1, 2, borderDelta); BufferedImage stateImage = SubstanceCoreUtilities.getBlankImage(this.size, this.size); Graphics2D g2d = stateImage.createGraphics(); g2d.translate((this.size - width) / 2.0f, 0); fillPainter.paintContourBackground(g2d, slider, width, this.size, contour, false, fillScheme, true); float borderThickness = SubstanceSizeUtils.getBorderStrokeWidth(); GeneralPath contourInner = SubstanceOutlineUtilities.getTriangleButtonOutline(width, this.size - 1, 2, borderThickness + borderDelta); borderPainter.paintBorder(g2d, slider, width, this.size, contour, contourInner, borderScheme); g2d.dispose(); if (this.isMirrorred) stateImage = SubstanceImageCreator.getRotated(stateImage, 2, false); return new HiDpiAwareIcon(stateImage); } /* * (non-Javadoc) * * @see javax.swing.Icon#paintIcon(java.awt.Component, * java.awt.Graphics, int, int) */ public void paintIcon(Component c, Graphics g, int x, int y) { if (!(g instanceof Graphics2D)) { return; } JSlider slider = (JSlider) c; TransitionAwareUI transitionAwareUI = (TransitionAwareUI) slider.getUI(); StateTransitionTracker stateTransitionTracker = transitionAwareUI .getTransitionTracker(); Icon iconToDraw = getIcon(slider, stateTransitionTracker); Graphics2D g2d = (Graphics2D) g.create(); g2d.translate(x, y); iconToDraw.paintIcon(c, g, 0, 0); g2d.dispose(); } /* * (non-Javadoc) * * @see javax.swing.Icon#getIconWidth() */ public int getIconWidth() { return this.size; } /* * (non-Javadoc) * * @see javax.swing.Icon#getIconHeight() */ public int getIconHeight() { return this.size; } } /** * Round icon for sliders in {@link SubstanceSliderUI}. * * @author Kirill Grouchnikov */ private static class SliderRoundIcon implements Icon, UIResource { /** * Icon hash. */ private static LazyResettableHashMap<HiDpiAwareIcon> icons = new LazyResettableHashMap<HiDpiAwareIcon>( "SubstanceIconFactory.SliderRoundIcon"); /** * The size of <code>this</code> icon. */ private int size; /** * Simple constructor. * * @param size * The size of <code>this</code> icon. */ public SliderRoundIcon(int size) { this.size = size; } /** * Retrieves icon that matches the specified state of the slider thumb. * * @param state * Slider state. * @param prevState * The previous slider state. * @param slider * The slider itself. * @param sliderIcon * The slider icon. * @return Icon that matches the specified state of the slider thumb. */ private HiDpiAwareIcon getIcon(JSlider slider, StateTransitionTracker stateTransitionTracker) { StateTransitionTracker.ModelStateInfo modelStateInfo = stateTransitionTracker .getModelStateInfo(); Map<ComponentState, StateTransitionTracker.StateContributionInfo> activeStates = modelStateInfo .getStateContributionMap(); ComponentState currState = stateTransitionTracker.getModelStateInfo() .getCurrModelState(); float activeStrength = stateTransitionTracker.getActiveStrength(); float width = this.size * (2.0f + activeStrength) / 3.0f; SubstanceFillPainter fillPainter = SubstanceCoreUtilities.getFillPainter(slider); SubstanceBorderPainter borderPainter = SubstanceCoreUtilities.getBorderPainter(slider); SubstanceColorScheme baseFillScheme = SubstanceColorSchemeUtilities .getColorScheme(slider, currState); SubstanceColorScheme baseBorderScheme = SubstanceColorSchemeUtilities .getColorScheme(slider, ColorSchemeAssociationKind.BORDER, currState); HashMapKey baseKey = SubstanceCoreUtilities.getHashKey(this.size, width, baseFillScheme.getDisplayName(), baseBorderScheme.getDisplayName(), fillPainter.getDisplayName(), borderPainter.getDisplayName()); HiDpiAwareIcon baseLayer = SliderRoundIcon.icons.get(baseKey); if (baseLayer == null) { baseLayer = getSingleLayer(slider, width, fillPainter, borderPainter, baseFillScheme, baseBorderScheme); SliderRoundIcon.icons.put(baseKey, baseLayer); } if (currState.isDisabled() || (activeStates.size() == 1)) return baseLayer; BufferedImage result = SubstanceCoreUtilities.getBlankImage(baseLayer.getIconWidth(), baseLayer.getIconHeight()); Graphics2D g2d = result.createGraphics(); baseLayer.paintIcon(slider, g2d, 0, 0); for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : activeStates .entrySet()) { ComponentState activeState = activeEntry.getKey(); if (activeState == currState) continue; float contribution = activeEntry.getValue().getContribution(); if (contribution == 0.0f) continue; SubstanceColorScheme fillScheme = SubstanceColorSchemeUtilities .getColorScheme(slider, activeState); SubstanceColorScheme borderScheme = SubstanceColorSchemeUtilities .getColorScheme(slider, ColorSchemeAssociationKind.BORDER, activeState); HashMapKey key = SubstanceCoreUtilities.getHashKey(this.size, width, fillScheme.getDisplayName(), borderScheme.getDisplayName(), fillPainter.getDisplayName(), borderPainter.getDisplayName()); HiDpiAwareIcon layer = SliderRoundIcon.icons.get(key); if (layer == null) { layer = getSingleLayer(slider, width, fillPainter, borderPainter, fillScheme, borderScheme); SliderRoundIcon.icons.put(key, layer); } g2d.setComposite(AlphaComposite.SrcOver.derive(contribution)); layer.paintIcon(slider, g2d, 0, 0); } g2d.dispose(); return new HiDpiAwareIcon(result); } private HiDpiAwareIcon getSingleLayer(JSlider slider, float width, SubstanceFillPainter fillPainter, SubstanceBorderPainter borderPainter, SubstanceColorScheme fillScheme, SubstanceColorScheme borderScheme) { float borderDelta = SubstanceSizeUtils.getBorderStrokeWidth() / 2.0f; Shape contour = new Ellipse2D.Float(borderDelta, borderDelta, width - 2 * borderDelta - 1, width - 2 * borderDelta - 1); BufferedImage stateImage = SubstanceCoreUtilities.getBlankImage(this.size, this.size); Graphics2D g2d = stateImage.createGraphics(); float delta = (this.size - width) / 2.0f; g2d.translate(delta, delta); fillPainter.paintContourBackground(g2d, slider, width, this.size, contour, false, fillScheme, true); float borderThickness = SubstanceSizeUtils.getBorderStrokeWidth(); Shape contourInner = new Ellipse2D.Float(borderDelta + borderThickness, borderDelta + borderThickness, width - 2 * borderDelta - 2 * borderThickness - 1, width - 2 * borderDelta - 2 * borderThickness - 1); borderPainter.paintBorder(g2d, slider, width, this.size, contour, contourInner, borderScheme); return new HiDpiAwareIcon(stateImage); } /* * (non-Javadoc) * * @see javax.swing.Icon#paintIcon(java.awt.Component, * java.awt.Graphics, int, int) */ public void paintIcon(Component c, Graphics g, int x, int y) { if (!(g instanceof Graphics2D)) { return; } JSlider slider = (JSlider) c; TransitionAwareUI transitionAwareUI = (TransitionAwareUI) slider.getUI(); StateTransitionTracker stateTransitionTracker = transitionAwareUI .getTransitionTracker(); Icon iconToDraw = getIcon(slider, stateTransitionTracker); Graphics2D g2d = (Graphics2D) g.create(); g2d.translate(x, y); iconToDraw.paintIcon(c, g, 0, 0); g2d.dispose(); } /* * (non-Javadoc) * * @see javax.swing.Icon#getIconWidth() */ public int getIconWidth() { return this.size; } /* * (non-Javadoc) * * @see javax.swing.Icon#getIconHeight() */ public int getIconHeight() { return this.size; } } /** * Icon for vertical slider in {@link SubstanceSliderUI}. * * @author Kirill Grouchnikov */ private static class SliderVerticalIcon implements Icon, UIResource { /** * Icon hash. */ private static LazyResettableHashMap<HiDpiAwareIcon> icons = new LazyResettableHashMap<HiDpiAwareIcon>( "SubstanceIconFactory.SliderVerticalIcon"); /** * The size of <code>this</code> icon. */ private int size; /** * Indication whether the icon is mirrorred. */ private boolean isMirrorred; /** * Simple constructor. * * @param size * The size of <code>this</code> icon. * @param isMirrorred * Indication whether the icon should be mirrored. */ public SliderVerticalIcon(int size, boolean isMirrorred) { this.size = size; this.isMirrorred = isMirrorred; } /** * Retrieves icon that matches the specified state of the slider thumb. * * @param state * Slider state. * @param prevState * The previous slider state. * @param slider * The slider itself. * @param sliderIcon * The slider icon. * @return Icon that matches the specified state of the slider thumb. */ private HiDpiAwareIcon getIcon(JSlider slider, StateTransitionTracker stateTransitionTracker) { StateTransitionTracker.ModelStateInfo modelStateInfo = stateTransitionTracker .getModelStateInfo(); Map<ComponentState, StateTransitionTracker.StateContributionInfo> activeStates = modelStateInfo .getStateContributionMap(); ComponentState currState = stateTransitionTracker.getModelStateInfo() .getCurrModelState(); float activeStrength = stateTransitionTracker.getActiveStrength(); int height = (int) (this.size * (2.0 + activeStrength) / 3.0); height = Math.min(height, this.size - 2); int delta = (this.size - height) / 2 - 1; SubstanceFillPainter fillPainter = SubstanceCoreUtilities.getFillPainter(slider); SubstanceBorderPainter borderPainter = SubstanceCoreUtilities.getBorderPainter(slider); SubstanceColorScheme baseFillScheme = SubstanceColorSchemeUtilities .getColorScheme(slider, currState); SubstanceColorScheme baseBorderScheme = SubstanceColorSchemeUtilities .getColorScheme(slider, ColorSchemeAssociationKind.BORDER, currState); HashMapKey baseKey = SubstanceCoreUtilities.getHashKey(this.size, height, slider.getComponentOrientation(), baseFillScheme.getDisplayName(), baseBorderScheme.getDisplayName(), fillPainter.getDisplayName(), borderPainter.getDisplayName(), this.isMirrorred); HiDpiAwareIcon baseLayer = SliderVerticalIcon.icons.get(baseKey); if (baseLayer == null) { baseLayer = getSingleLayer(slider, height, delta, fillPainter, borderPainter, baseFillScheme, baseBorderScheme); SliderVerticalIcon.icons.put(baseKey, baseLayer); } if (currState.isDisabled() || (activeStates.size() == 1)) return baseLayer; BufferedImage result = SubstanceCoreUtilities.getBlankImage(baseLayer.getIconWidth(), baseLayer.getIconHeight()); Graphics2D g2d = result.createGraphics(); baseLayer.paintIcon(slider, g2d, 0, 0); for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : activeStates .entrySet()) { ComponentState activeState = activeEntry.getKey(); if (activeState == currState) continue; float contribution = activeEntry.getValue().getContribution(); if (contribution == 0.0f) continue; SubstanceColorScheme fillScheme = SubstanceColorSchemeUtilities .getColorScheme(slider, activeState); SubstanceColorScheme borderScheme = SubstanceColorSchemeUtilities .getColorScheme(slider, ColorSchemeAssociationKind.BORDER, activeState); HashMapKey key = SubstanceCoreUtilities.getHashKey(this.size, height, slider.getComponentOrientation(), fillScheme.getDisplayName(), borderScheme.getDisplayName(), fillPainter.getDisplayName(), borderPainter.getDisplayName(), this.isMirrorred); HiDpiAwareIcon layer = SliderVerticalIcon.icons.get(key); if (layer == null) { layer = getSingleLayer(slider, height, delta, fillPainter, borderPainter, fillScheme, borderScheme); SliderVerticalIcon.icons.put(key, layer); } g2d.setComposite(AlphaComposite.SrcOver.derive(contribution)); layer.paintIcon(slider, g2d, 0, 0); } g2d.dispose(); return new HiDpiAwareIcon(result); } private HiDpiAwareIcon getSingleLayer(JSlider slider, int height, int delta, SubstanceFillPainter fillPainter, SubstanceBorderPainter borderPainter, SubstanceColorScheme fillScheme, SubstanceColorScheme borderScheme) { float borderDelta = SubstanceSizeUtils.getBorderStrokeWidth() / 2.0f; Shape contour = SubstanceOutlineUtilities.getTriangleButtonOutline(height, this.size - 1, 2, borderDelta); BufferedImage stateImage = SubstanceCoreUtilities.getBlankImage(this.size - 1, this.size - 1); Graphics2D g2d = stateImage.createGraphics(); g2d.translate(delta, 0); fillPainter.paintContourBackground(g2d, slider, height, this.size, contour, false, fillScheme, true); float borderThickness = SubstanceSizeUtils.getBorderStrokeWidth(); GeneralPath contourInner = SubstanceOutlineUtilities.getTriangleButtonOutline(height, this.size - 1, 2, borderThickness + borderDelta); borderPainter.paintBorder(g2d, slider, height, this.size - 1, contour, contourInner, borderScheme); if (this.isMirrorred) stateImage = SubstanceImageCreator.getRotated(stateImage, 1, false); else stateImage = SubstanceImageCreator.getRotated(stateImage, 3, false); if (!slider.getComponentOrientation().isLeftToRight()) { stateImage = SubstanceImageCreator.getRotated(stateImage, 2, false); } return new HiDpiAwareIcon(stateImage); } /* * (non-Javadoc) * * @see javax.swing.Icon#paintIcon(java.awt.Component, * java.awt.Graphics, int, int) */ public void paintIcon(Component c, Graphics g, int x, int y) { if (!(g instanceof Graphics2D)) { return; } JSlider slider = (JSlider) c; TransitionAwareUI transitionAwareUI = (TransitionAwareUI) slider.getUI(); StateTransitionTracker stateTransitionTracker = transitionAwareUI .getTransitionTracker(); Icon iconToDraw = getIcon(slider, stateTransitionTracker); Graphics2D g2d = (Graphics2D) g.create(); g2d.translate(x, y); iconToDraw.paintIcon(c, g, 0, 0); g2d.dispose(); } /* * (non-Javadoc) * * @see javax.swing.Icon#getIconWidth() */ public int getIconWidth() { return this.size - 1; } /* * (non-Javadoc) * * @see javax.swing.Icon#getIconHeight() */ public int getIconHeight() { return this.size - 1; } } /** * Collapse / expand icons for JTrees in {@link SubstanceTreeUI}. * * @author Kirill Grouchnikov */ private static class TreeIcon implements Icon, UIResource, IsHiDpiAware { /** * Icon hash. */ private static LazyResettableHashMap<HiDpiAwareIcon> icons = new LazyResettableHashMap<HiDpiAwareIcon>( "SubstanceIconFactory.TreeIcon"); /** * The collapsed indication of this icon */ private boolean isCollapsed; private int size; /** * Simple constructor. * * @param isCollapsed * The collapsed indication of <code>this</code> icon. */ public TreeIcon(int size, boolean isCollapsed) { this.isCollapsed = isCollapsed; this.size = size; } @Override public boolean isHiDpiAware() { return true; } /** * Retrieves icon that matches the specified state of the slider thumb. * * @param state * Slider state. * @param prevState * The previous slider state. * @param slider * The slider itself. * @param sliderIcon * The slider icon. * @return Icon that matches the specified state of the slider thumb. */ private static HiDpiAwareIcon getIcon(JTree tree, boolean isCollapsed) { ComponentState state = ((tree == null) || tree.isEnabled()) ? ComponentState.ENABLED : ComponentState.DISABLED_UNSELECTED; SubstanceColorScheme fillScheme = SubstanceColorSchemeUtilities.getColorScheme(tree, state); SubstanceColorScheme borderScheme = SubstanceColorSchemeUtilities.getColorScheme(tree, ColorSchemeAssociationKind.BORDER, state); SubstanceColorScheme markScheme = SubstanceColorSchemeUtilities.getColorScheme(tree, ColorSchemeAssociationKind.MARK, state); int fontSize = SubstanceSizeUtils.getComponentFontSize(tree); HashMapKey key = SubstanceCoreUtilities.getHashKey(fontSize, fillScheme.getDisplayName(), borderScheme.getDisplayName(), markScheme.getDisplayName(), isCollapsed); HiDpiAwareIcon result = TreeIcon.icons.get(key); if (result != null) return result; result = new HiDpiAwareIcon( SubstanceImageCreator.getTreeIcon(tree, fillScheme, borderScheme, markScheme, isCollapsed)); TreeIcon.icons.put(key, result); return result; } /* * (non-Javadoc) * * @see javax.swing.Icon#paintIcon(java.awt.Component, * java.awt.Graphics, int, int) */ public void paintIcon(Component c, Graphics g, int x, int y) { if (!(g instanceof Graphics2D)) { return; } // The following check is here because some applications // (like JIDE's ExpandablePanel) may decide to use the // "Tree.collapsedIcon" and "Tree.expandedIcon" UIManager // entries to paint on non-JTree components. Sigh. JTree tree = (c instanceof JTree) ? (JTree) c : null; HiDpiAwareIcon iconToDraw = TreeIcon.getIcon(tree, this.isCollapsed); Graphics2D g2d = (Graphics2D) g.create(); g2d.translate(x, y); iconToDraw.paintIcon(c, g2d, 0, 0); g2d.dispose(); } /* * (non-Javadoc) * * @see javax.swing.Icon#getIconWidth() */ public int getIconWidth() { return this.size; } /* * (non-Javadoc) * * @see javax.swing.Icon#getIconHeight() */ public int getIconHeight() { return this.size; } } /** * Icon kind of a title pane button. * * @author Kirill Grocuhnikov. */ public enum IconKind { /** * Icon of a close button. */ CLOSE, /** * Icon of a minimize button. */ MINIMIZE, /** * Icon of a maximize button. */ MAXIMIZE, /** * Icon of a restore button. */ RESTORE; } /** * Cache of title pane icons. */ private static final Map<IconKind, LazyResettableHashMap<HiDpiAwareIcon>> titlePaneIcons = SubstanceIconFactory .createTitlePaneIcons(); /** * Creates an empty map of title pane icons. * * @return Empty map of title pane icons. */ private static Map<IconKind, LazyResettableHashMap<HiDpiAwareIcon>> createTitlePaneIcons() { Map<IconKind, LazyResettableHashMap<HiDpiAwareIcon>> result = new HashMap<IconKind, LazyResettableHashMap<HiDpiAwareIcon>>(); result.put(IconKind.CLOSE, new LazyResettableHashMap<HiDpiAwareIcon>("Close title pane icons")); result.put(IconKind.MINIMIZE, new LazyResettableHashMap<HiDpiAwareIcon>("Minimize title pane icons")); result.put(IconKind.MAXIMIZE, new LazyResettableHashMap<HiDpiAwareIcon>("Maximize title pane icons")); result.put(IconKind.RESTORE, new LazyResettableHashMap<HiDpiAwareIcon>("Restore title pane icons")); return result; } /** * Returns title pane icon of the specified kind. * * @param iconKind * Icon kind. * @param scheme * Color scheme. * @return Title pane icon of the specified kind. */ public static HiDpiAwareIcon getTitlePaneIcon(IconKind iconKind, SubstanceColorScheme scheme, SubstanceColorScheme backgroundScheme) { LazyResettableHashMap<HiDpiAwareIcon> kindMap = SubstanceIconFactory.titlePaneIcons .get(iconKind); HashMapKey key = SubstanceCoreUtilities.getHashKey(scheme.getDisplayName(), backgroundScheme.getDisplayName()); HiDpiAwareIcon result = kindMap.get(key); if (result != null) return result; switch (iconKind) { case CLOSE: result = SubstanceImageCreator.getCloseIcon(scheme, backgroundScheme); break; case MINIMIZE: result = SubstanceImageCreator.getMinimizeIcon(scheme, backgroundScheme); break; case MAXIMIZE: result = SubstanceImageCreator.getMaximizeIcon(scheme, backgroundScheme); break; case RESTORE: result = SubstanceImageCreator.getRestoreIcon(scheme, backgroundScheme); break; } kindMap.put(key, result); return result; } }