~ubuntu-branches/debian/stretch/insubstantial/stretch

« back to all changes in this revision

Viewing changes to substance/src/main/java/org/pushingpixels/substance/internal/utils/icon/ArrowButtonTransitionAwareIcon.java

  • Committer: Package Import Robot
  • Author(s): Felix Natter
  • Date: 2016-01-18 20:58:45 UTC
  • Revision ID: package-import@ubuntu.com-20160118205845-crbmrkda61qsi5qa
Tags: upstream-7.3+dfsg2
ImportĀ upstreamĀ versionĀ 7.3+dfsg2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2005-2010 Substance Kirill Grouchnikov. All Rights Reserved.
 
3
 *
 
4
 * Redistribution and use in source and binary forms, with or without 
 
5
 * modification, are permitted provided that the following conditions are met:
 
6
 * 
 
7
 *  o Redistributions of source code must retain the above copyright notice, 
 
8
 *    this list of conditions and the following disclaimer. 
 
9
 *     
 
10
 *  o Redistributions in binary form must reproduce the above copyright notice, 
 
11
 *    this list of conditions and the following disclaimer in the documentation 
 
12
 *    and/or other materials provided with the distribution. 
 
13
 *     
 
14
 *  o Neither the name of Substance Kirill Grouchnikov nor the names of 
 
15
 *    its contributors may be used to endorse or promote products derived 
 
16
 *    from this software without specific prior written permission. 
 
17
 *     
 
18
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 
19
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
 
20
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 
21
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
 
22
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 
23
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 
24
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
 
25
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 
26
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
 
27
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
 
28
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 
29
 */
 
30
package org.pushingpixels.substance.internal.utils.icon;
 
31
 
 
32
import java.awt.AlphaComposite;
 
33
import java.awt.Component;
 
34
import java.awt.Graphics;
 
35
import java.awt.Graphics2D;
 
36
import java.awt.image.BufferedImage;
 
37
import java.util.Map;
 
38
 
 
39
import javax.swing.AbstractButton;
 
40
import javax.swing.Icon;
 
41
import javax.swing.ImageIcon;
 
42
import javax.swing.JComponent;
 
43
import javax.swing.JMenu;
 
44
import javax.swing.SwingConstants;
 
45
 
 
46
import org.pushingpixels.substance.api.ColorSchemeAssociationKind;
 
47
import org.pushingpixels.substance.api.ComponentState;
 
48
import org.pushingpixels.substance.api.ComponentStateFacet;
 
49
import org.pushingpixels.substance.api.SubstanceColorScheme;
 
50
import org.pushingpixels.substance.internal.animation.StateTransitionTracker;
 
51
import org.pushingpixels.substance.internal.animation.TransitionAwareUI;
 
52
import org.pushingpixels.substance.internal.utils.HashMapKey;
 
53
import org.pushingpixels.substance.internal.utils.LazyResettableHashMap;
 
54
import org.pushingpixels.substance.internal.utils.SubstanceColorSchemeUtilities;
 
55
import org.pushingpixels.substance.internal.utils.SubstanceCoreUtilities;
 
56
import org.pushingpixels.substance.internal.utils.SubstanceImageCreator;
 
57
import org.pushingpixels.substance.internal.utils.SubstanceSizeUtils;
 
58
 
 
59
/**
 
60
 * Transition aware implementation of arrow button icons. Used for implementing
 
61
 * icons of scroll bar buttons, combobox buttons, menus and more.
 
62
 * 
 
63
 * @author Kirill Grouchnikov
 
64
 */
 
65
@TransitionAware
 
66
public class ArrowButtonTransitionAwareIcon implements Icon {
 
67
        /**
 
68
         * Icon cache to speed up the subsequent icon painting. The basic assumption
 
69
         * is that the {@link #delegate} returns an icon that paints the same for
 
70
         * the same parameters.
 
71
         */
 
72
        private static LazyResettableHashMap<Icon> iconMap = new LazyResettableHashMap<Icon>(
 
73
                        "ButtonArrowTransitionAwareIcon");
 
74
 
 
75
        /**
 
76
         * Arrow icon orientation. Must be one of {@link SwingConstants#NORTH},
 
77
         * {@link SwingConstants#SOUTH}, {@link SwingConstants#EAST} or
 
78
         * {@link SwingConstants#WEST}.
 
79
         */
 
80
        private int orientation;
 
81
 
 
82
        /**
 
83
         * Icon width.
 
84
         */
 
85
        protected int iconWidth;
 
86
 
 
87
        /**
 
88
         * Icon height.
 
89
         */
 
90
        protected int iconHeight;
 
91
 
 
92
        /**
 
93
         * Delegate to compute the actual icons.
 
94
         */
 
95
        protected TransitionAwareIcon.Delegate delegate;
 
96
 
 
97
        protected JComponent component;
 
98
 
 
99
        private TransitionAwareIcon.TransitionAwareUIDelegate transitionAwareUIDelegate;
 
100
 
 
101
        public ArrowButtonTransitionAwareIcon(final AbstractButton button,
 
102
                        int orientation) {
 
103
                this(button, new TransitionAwareIcon.TransitionAwareUIDelegate() {
 
104
                        @Override
 
105
                        public TransitionAwareUI getTransitionAwareUI() {
 
106
                                return (TransitionAwareUI) button.getUI();
 
107
                        }
 
108
                }, orientation);
 
109
        }
 
110
 
 
111
        /**
 
112
         * Creates an arrow icon.
 
113
         * 
 
114
         * @param component
 
115
         *            Arrow button.
 
116
         * @param orientation
 
117
         *            Arrow icon orientation.
 
118
         */
 
119
        public ArrowButtonTransitionAwareIcon(
 
120
                        final JComponent component,
 
121
                        TransitionAwareIcon.TransitionAwareUIDelegate transitionAwareUIDelegate,
 
122
                        final int orientation) {
 
123
                this.component = component;
 
124
                this.transitionAwareUIDelegate = transitionAwareUIDelegate;
 
125
                this.orientation = orientation;
 
126
                this.delegate = new TransitionAwareIcon.Delegate() {
 
127
                        @Override
 
128
                        public Icon getColorSchemeIcon(SubstanceColorScheme scheme) {
 
129
                                int fontSize = SubstanceSizeUtils
 
130
                                                .getComponentFontSize(component);
 
131
                                return SubstanceImageCreator.getArrowIcon(fontSize,
 
132
                                                orientation, scheme);
 
133
                        }
 
134
                };
 
135
 
 
136
                this.iconWidth = this.delegate.getColorSchemeIcon(
 
137
                                SubstanceColorSchemeUtilities.getColorScheme(component,
 
138
                                                ComponentState.ENABLED)).getIconWidth();
 
139
                this.iconHeight = this.delegate.getColorSchemeIcon(
 
140
                                SubstanceColorSchemeUtilities.getColorScheme(component,
 
141
                                                ComponentState.ENABLED)).getIconHeight();
 
142
        }
 
143
 
 
144
        @Override
 
145
        public void paintIcon(Component c, Graphics g, int x, int y) {
 
146
                this.getIconToPaint().paintIcon(c, g, x, y);
 
147
        }
 
148
 
 
149
        /**
 
150
         * Returns the icon to be painted for the current state of the button.
 
151
         * 
 
152
         * @return Icon to be painted.
 
153
         */
 
154
        private Icon getIconToPaint() {
 
155
                boolean isMenu = (this.component instanceof JMenu);
 
156
                StateTransitionTracker stateTransitionTracker = this.transitionAwareUIDelegate
 
157
                                .getTransitionAwareUI().getTransitionTracker();
 
158
                StateTransitionTracker.ModelStateInfo modelStateInfo = stateTransitionTracker
 
159
                                .getModelStateInfo();
 
160
                Map<ComponentState, StateTransitionTracker.StateContributionInfo> activeStates = isMenu ? modelStateInfo
 
161
                                .getStateNoSelectionContributionMap()
 
162
                                : modelStateInfo.getStateContributionMap();
 
163
                ComponentState currState = isMenu ? modelStateInfo
 
164
                                .getCurrModelStateNoSelection() : modelStateInfo
 
165
                                .getCurrModelState();
 
166
 
 
167
                // Use HIGHLIGHT for rollover menus (arrow icons)
 
168
                // and MARK for the rest
 
169
                ColorSchemeAssociationKind baseAssociationKind = isMenu
 
170
                                && currState.isFacetActive(ComponentStateFacet.ROLLOVER) ? ColorSchemeAssociationKind.HIGHLIGHT
 
171
                                : ColorSchemeAssociationKind.MARK;
 
172
                SubstanceColorScheme baseScheme = SubstanceColorSchemeUtilities
 
173
                                .getColorScheme(this.component, baseAssociationKind, currState);
 
174
                float baseAlpha = SubstanceColorSchemeUtilities.getAlpha(
 
175
                                this.component, currState);
 
176
 
 
177
                HashMapKey keyBase = SubstanceCoreUtilities.getHashKey(this.component
 
178
                                .getClass().getName(), this.orientation, SubstanceSizeUtils
 
179
                                .getComponentFontSize(this.component), baseScheme
 
180
                                .getDisplayName(), baseAlpha);
 
181
                Icon layerBase = iconMap.get(keyBase);
 
182
                if (layerBase == null) {
 
183
                        Icon baseFullOpacity = this.delegate.getColorSchemeIcon(baseScheme);
 
184
                        if (baseAlpha == 1.0f) {
 
185
                                layerBase = baseFullOpacity;
 
186
                                iconMap.put(keyBase, layerBase);
 
187
                        } else {
 
188
                                BufferedImage baseImage = SubstanceCoreUtilities.getBlankImage(
 
189
                                                baseFullOpacity.getIconWidth(), baseFullOpacity
 
190
                                                                .getIconHeight());
 
191
                                Graphics2D g2base = baseImage.createGraphics();
 
192
                                g2base.setComposite(AlphaComposite.SrcOver.derive(baseAlpha));
 
193
                                baseFullOpacity.paintIcon(this.component, g2base, 0, 0);
 
194
                                g2base.dispose();
 
195
                                layerBase = new ImageIcon(baseImage);
 
196
                                iconMap.put(keyBase, layerBase);
 
197
                        }
 
198
                }
 
199
                // System.out.println("Contribution map in painting");
 
200
                // for (Map.Entry<ComponentState,
 
201
                // StateTransitionTracker.StateContributionInfo> existing : activeStates
 
202
                // .entrySet()) {
 
203
                // System.out.println("\t" + existing.getKey() + " in ["
 
204
                // + existing.getValue().start + ":" + existing.getValue().end
 
205
                // + "] : " + existing.getValue().curr);
 
206
                // }
 
207
 
 
208
                if (currState.isDisabled() || (activeStates.size() == 1)) {
 
209
                        return layerBase;
 
210
                }
 
211
 
 
212
                BufferedImage result = SubstanceCoreUtilities.getBlankImage(layerBase
 
213
                                .getIconWidth(), layerBase.getIconHeight());
 
214
                Graphics2D g2d = result.createGraphics();
 
215
                // draw the base layer
 
216
                // System.out.println("Painting currState " + currState + ":" +
 
217
                // baseAlpha);
 
218
                layerBase.paintIcon(this.component, g2d, 0, 0);
 
219
 
 
220
                // draw the other active layers
 
221
                for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : activeStates
 
222
                                .entrySet()) {
 
223
                        ComponentState activeState = activeEntry.getKey();
 
224
                        // System.out.println("Painting state " + activeState + "[curr is "
 
225
                        // + currState + "] with " + activeEntry.getValue());
 
226
                        if (activeState == currState)
 
227
                                continue;
 
228
 
 
229
                        float stateContribution = activeEntry.getValue().getContribution();
 
230
                        // System.out.println("Painting activeState "
 
231
                        // + activeState
 
232
                        // + ":"
 
233
                        // + stateContribution
 
234
                        // + "*"
 
235
                        // + SubstanceColorSchemeUtilities.getAlpha(this.component,
 
236
                        // activeState));
 
237
                        if (stateContribution > 0.0f) {
 
238
                                g2d.setComposite(AlphaComposite.SrcOver
 
239
                                                .derive(stateContribution));
 
240
 
 
241
                                ColorSchemeAssociationKind associationKind = isMenu
 
242
                                                && activeState
 
243
                                                                .isFacetActive(ComponentStateFacet.ROLLOVER) ? ColorSchemeAssociationKind.HIGHLIGHT
 
244
                                                : ColorSchemeAssociationKind.MARK;
 
245
                                SubstanceColorScheme scheme = SubstanceColorSchemeUtilities
 
246
                                                .getColorScheme(this.component, associationKind,
 
247
                                                                activeState);
 
248
                                float alpha = SubstanceColorSchemeUtilities.getAlpha(
 
249
                                                this.component, activeState);
 
250
 
 
251
                                HashMapKey key = SubstanceCoreUtilities
 
252
                                                .getHashKey(this.component.getClass().getName(),
 
253
                                                                this.orientation, SubstanceSizeUtils
 
254
                                                                                .getComponentFontSize(this.component),
 
255
                                                                scheme.getDisplayName(), alpha);
 
256
                                Icon layer = iconMap.get(key);
 
257
                                if (layer == null) {
 
258
                                        Icon fullOpacity = this.delegate.getColorSchemeIcon(scheme);
 
259
                                        if (alpha == 1.0f) {
 
260
                                                layer = fullOpacity;
 
261
                                                iconMap.put(key, layer);
 
262
                                        } else {
 
263
                                                BufferedImage image = SubstanceCoreUtilities
 
264
                                                                .getBlankImage(fullOpacity.getIconWidth(),
 
265
                                                                                fullOpacity.getIconHeight());
 
266
                                                Graphics2D g2layer = image.createGraphics();
 
267
                                                g2layer.setComposite(AlphaComposite.SrcOver
 
268
                                                                .derive(alpha));
 
269
                                                fullOpacity.paintIcon(this.component, g2layer, 0, 0);
 
270
                                                g2layer.dispose();
 
271
                                                layer = new ImageIcon(image);
 
272
                                                iconMap.put(key, layer);
 
273
                                        }
 
274
                                }
 
275
                                layer.paintIcon(this.component, g2d, 0, 0);
 
276
                        }
 
277
                }
 
278
                g2d.dispose();
 
279
                return new ImageIcon(result);
 
280
                //
 
281
                //
 
282
                // SubstanceColorScheme currScheme = SubstanceColorSchemeUtilities
 
283
                // .getColorScheme(this.component, currAssociationKind, currState);
 
284
                //
 
285
                // SubstanceColorScheme prevScheme = currScheme;
 
286
                //
 
287
                // // Use HIGHLIGHT for rollover menus (arrow icons)
 
288
                // // and MARK for the rest
 
289
                // if (prevState != currState) {
 
290
                // ColorSchemeAssociationKind prevAssociationKind = (this.component
 
291
                // instanceof JMenu)
 
292
                // && prevState.isFacetActive(AnimationFacet.ROLLOVER) ?
 
293
                // ColorSchemeAssociationKind.HIGHLIGHT
 
294
                // : ColorSchemeAssociationKind.MARK;
 
295
                // prevScheme = SubstanceColorSchemeUtilities.getColorScheme(
 
296
                // this.component, prevAssociationKind, prevState);
 
297
                // }
 
298
                // cyclePos = stateTransitionTracker.getModelTransitionPosition();
 
299
                // float currAlpha = SubstanceColorSchemeUtilities.getAlpha(
 
300
                // this.component, currState);
 
301
                // float prevAlpha = SubstanceColorSchemeUtilities.getAlpha(
 
302
                // this.component, prevState);
 
303
                //
 
304
                // HashMapKey key = SubstanceCoreUtilities.getHashKey(this.component
 
305
                // .getClass().getName(), this.orientation, SubstanceSizeUtils
 
306
                // .getComponentFontSize(this.component), currScheme
 
307
                // .getDisplayName(), prevScheme.getDisplayName(), currAlpha,
 
308
                // prevAlpha, cyclePos);
 
309
                // Icon result = iconMap.get(key);
 
310
                // if (result == null) {
 
311
                // Icon icon = this.delegate.getColorSchemeIcon(currScheme);
 
312
                // Icon prevIcon = this.delegate.getColorSchemeIcon(prevScheme);
 
313
                //
 
314
                // BufferedImage temp = SubstanceCoreUtilities.getBlankImage(icon
 
315
                // .getIconWidth(), icon.getIconHeight());
 
316
                // Graphics2D g2d = temp.createGraphics();
 
317
                //
 
318
                // if (currScheme == prevScheme) {
 
319
                // // same scheme - can paint just the current icon, no matter
 
320
                // // what the cycle position is.
 
321
                // g2d.setComposite(AlphaComposite.getInstance(
 
322
                // AlphaComposite.SRC_OVER, currAlpha));
 
323
                // icon.paintIcon(this.component, g2d, 0, 0);
 
324
                // } else {
 
325
                // // make optimizations for limit values of the cycle position.
 
326
                // if (cyclePos < 1.0f) {
 
327
                // g2d.setComposite(AlphaComposite.SrcOver.derive(prevAlpha));
 
328
                // prevIcon.paintIcon(this.component, g2d, 0, 0);
 
329
                // }
 
330
                // if (cyclePos > 0.0f) {
 
331
                // g2d.setComposite(AlphaComposite.SrcOver.derive(currAlpha
 
332
                // * cyclePos));
 
333
                // icon.paintIcon(this.component, g2d, 0, 0);
 
334
                // }
 
335
                // }
 
336
                //
 
337
                // result = new ImageIcon(temp);
 
338
                // iconMap.put(key, result);
 
339
                // g2d.dispose();
 
340
                // }
 
341
                //
 
342
                // return result;
 
343
        }
 
344
 
 
345
        /*
 
346
         * (non-Javadoc)
 
347
         * 
 
348
         * @see javax.swing.Icon#getIconHeight()
 
349
         */
 
350
        @Override
 
351
    public int getIconHeight() {
 
352
                return this.iconHeight;
 
353
        }
 
354
 
 
355
        /*
 
356
         * (non-Javadoc)
 
357
         * 
 
358
         * @see javax.swing.Icon#getIconWidth()
 
359
         */
 
360
        @Override
 
361
    public int getIconWidth() {
 
362
                return this.iconWidth;
 
363
        }
 
364
}