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

« back to all changes in this revision

Viewing changes to substance/src/main/java/org/pushingpixels/substance/internal/ui/SubstanceRadioButtonUI.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.ui;
 
31
 
 
32
import java.awt.*;
 
33
import java.awt.event.MouseEvent;
 
34
import java.awt.image.BufferedImage;
 
35
import java.beans.PropertyChangeEvent;
 
36
import java.beans.PropertyChangeListener;
 
37
import java.util.Map;
 
38
 
 
39
import javax.swing.*;
 
40
import javax.swing.border.Border;
 
41
import javax.swing.plaf.ComponentUI;
 
42
import javax.swing.plaf.UIResource;
 
43
import javax.swing.plaf.basic.*;
 
44
import javax.swing.text.View;
 
45
 
 
46
import org.pushingpixels.substance.api.*;
 
47
import org.pushingpixels.substance.api.painter.border.SubstanceBorderPainter;
 
48
import org.pushingpixels.substance.api.painter.fill.SubstanceFillPainter;
 
49
import org.pushingpixels.substance.internal.animation.StateTransitionTracker;
 
50
import org.pushingpixels.substance.internal.animation.TransitionAwareUI;
 
51
import org.pushingpixels.substance.internal.painter.BackgroundPaintingUtils;
 
52
import org.pushingpixels.substance.internal.utils.*;
 
53
 
 
54
/**
 
55
 * UI for radio buttons in <b>Substance </b> look and feel.
 
56
 * 
 
57
 * @author Kirill Grouchnikov
 
58
 */
 
59
public class SubstanceRadioButtonUI extends BasicRadioButtonUI implements
 
60
                TransitionAwareUI {
 
61
        /**
 
62
         * Property change listener. Listens on changes to
 
63
         * {@link AbstractButton#MODEL_CHANGED_PROPERTY} property.
 
64
         */
 
65
        protected PropertyChangeListener substancePropertyListener;
 
66
 
 
67
        /**
 
68
         * Associated toggle button.
 
69
         */
 
70
        protected JToggleButton button;
 
71
 
 
72
        /**
 
73
         * Icons for all component states
 
74
         */
 
75
        private static LazyResettableHashMap<Icon> icons = new LazyResettableHashMap<Icon>(
 
76
                        "SubstanceRadioButtonUI");
 
77
 
 
78
        protected StateTransitionTracker stateTransitionTracker;
 
79
 
 
80
        private Rectangle viewRect = new Rectangle();
 
81
 
 
82
        private Rectangle iconRect = new Rectangle();
 
83
 
 
84
        private Rectangle textRect = new Rectangle();
 
85
 
 
86
        /*
 
87
         * (non-Javadoc)
 
88
         * 
 
89
         * @seejavax.swing.plaf.basic.BasicButtonUI#installListeners(javax.swing.
 
90
         * AbstractButton)
 
91
         */
 
92
        @Override
 
93
        protected void installListeners(final AbstractButton b) {
 
94
                super.installListeners(b);
 
95
 
 
96
                this.stateTransitionTracker.registerModelListeners();
 
97
                this.stateTransitionTracker.registerFocusListeners();
 
98
 
 
99
                this.substancePropertyListener = new PropertyChangeListener() {
 
100
                        @Override
 
101
            public void propertyChange(PropertyChangeEvent evt) {
 
102
                                if (AbstractButton.MODEL_CHANGED_PROPERTY.equals(evt
 
103
                                                .getPropertyName())) {
 
104
                                        stateTransitionTracker.setModel((ButtonModel) evt
 
105
                                                        .getNewValue());
 
106
                                }
 
107
                                if ("font".equals(evt.getPropertyName())) {
 
108
                                        SwingUtilities.invokeLater(new Runnable() {
 
109
                                                @Override
 
110
                        public void run() {
 
111
                                                        b.updateUI();
 
112
                                                }
 
113
                                        });
 
114
                                }
 
115
                        }
 
116
                };
 
117
                b.addPropertyChangeListener(substancePropertyListener);
 
118
        }
 
119
 
 
120
        /*
 
121
         * (non-Javadoc)
 
122
         * 
 
123
         * @see
 
124
         * javax.swing.plaf.basic.BasicRadioButtonUI#installDefaults(javax.swing
 
125
         * .AbstractButton)
 
126
         */
 
127
        @Override
 
128
        protected void installDefaults(AbstractButton b) {
 
129
                super.installDefaults(b);
 
130
                Border border = b.getBorder();
 
131
                if (border == null || border instanceof UIResource) {
 
132
                        b.setBorder(SubstanceSizeUtils.getRadioButtonBorder(
 
133
                                        SubstanceSizeUtils.getComponentFontSize(b), b
 
134
                                                        .getComponentOrientation().isLeftToRight()));
 
135
                }
 
136
 
 
137
                button.setRolloverEnabled(true);
 
138
 
 
139
                LookAndFeel.installProperty(b, "iconTextGap", SubstanceSizeUtils
 
140
                                .getTextIconGap(SubstanceSizeUtils.getComponentFontSize(b)));
 
141
        }
 
142
 
 
143
        /*
 
144
         * (non-Javadoc)
 
145
         * 
 
146
         * @seejavax.swing.plaf.basic.BasicButtonUI#uninstallListeners(javax.swing.
 
147
         * AbstractButton)
 
148
         */
 
149
        @Override
 
150
        protected void uninstallListeners(AbstractButton b) {
 
151
                b.removePropertyChangeListener(substancePropertyListener);
 
152
                substancePropertyListener = null;
 
153
 
 
154
                this.stateTransitionTracker.unregisterModelListeners();
 
155
                this.stateTransitionTracker.unregisterFocusListeners();
 
156
 
 
157
                super.uninstallListeners(b);
 
158
        }
 
159
 
 
160
        /**
 
161
         * Returns the icon that matches the current and previous states of the
 
162
         * radio button.
 
163
         * 
 
164
         * @param button
 
165
         *            Button (should be {@link JRadioButton}).
 
166
         * @param stateTransitionTracker
 
167
         *            state of the checkbox.
 
168
         * @return Matching icon.
 
169
         */
 
170
        private static Icon getIcon(JToggleButton button,
 
171
                        StateTransitionTracker stateTransitionTracker) {
 
172
                StateTransitionTracker.ModelStateInfo modelStateInfo = stateTransitionTracker
 
173
                                .getModelStateInfo();
 
174
                Map<ComponentState, StateTransitionTracker.StateContributionInfo> activeStates = modelStateInfo
 
175
                                .getStateContributionMap();
 
176
 
 
177
                int fontSize = SubstanceSizeUtils.getComponentFontSize(button);
 
178
                int checkMarkSize = SubstanceSizeUtils.getRadioButtonMarkSize(fontSize);
 
179
 
 
180
                SubstanceFillPainter fillPainter = SubstanceCoreUtilities
 
181
                                .getFillPainter(button);
 
182
                SubstanceBorderPainter borderPainter = SubstanceCoreUtilities
 
183
                                .getBorderPainter(button);
 
184
                ComponentState currState = modelStateInfo.getCurrModelState();
 
185
 
 
186
                SubstanceColorScheme baseFillColorScheme = SubstanceColorSchemeUtilities
 
187
                                .getColorScheme(button, ColorSchemeAssociationKind.FILL,
 
188
                                                currState);
 
189
                SubstanceColorScheme baseMarkColorScheme = SubstanceColorSchemeUtilities
 
190
                                .getColorScheme(button, ColorSchemeAssociationKind.MARK,
 
191
                                                currState);
 
192
                SubstanceColorScheme baseBorderColorScheme = SubstanceColorSchemeUtilities
 
193
                                .getColorScheme(button, ColorSchemeAssociationKind.BORDER,
 
194
                                                currState);
 
195
                float visibility = stateTransitionTracker
 
196
                                .getFacetStrength(ComponentStateFacet.SELECTION);
 
197
 
 
198
                HashMapKey keyBase = SubstanceCoreUtilities.getHashKey(fontSize,
 
199
                                checkMarkSize, fillPainter.getDisplayName(), borderPainter
 
200
                                                .getDisplayName(),
 
201
                                baseFillColorScheme.getDisplayName(), baseMarkColorScheme
 
202
                                                .getDisplayName(), baseBorderColorScheme
 
203
                                                .getDisplayName(), visibility);
 
204
                Icon iconBase = icons.get(keyBase);
 
205
                if (iconBase == null) {
 
206
                        iconBase = new ImageIcon(SubstanceImageCreator.getRadioButton(
 
207
                                        button, fillPainter, borderPainter, checkMarkSize,
 
208
                                        currState, 0, baseFillColorScheme, baseMarkColorScheme,
 
209
                                        baseBorderColorScheme, visibility));
 
210
                        icons.put(keyBase, iconBase);
 
211
                }
 
212
                if (currState.isDisabled() || (activeStates.size() == 1)) {
 
213
                        return iconBase;
 
214
                }
 
215
 
 
216
                BufferedImage result = SubstanceCoreUtilities.getBlankImage(iconBase
 
217
                                .getIconWidth(), iconBase.getIconHeight());
 
218
                Graphics2D g2d = result.createGraphics();
 
219
                // draw the base layer
 
220
                iconBase.paintIcon(button, g2d, 0, 0);
 
221
 
 
222
                // draw other active layers
 
223
                for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : activeStates
 
224
                                .entrySet()) {
 
225
                        ComponentState activeState = activeEntry.getKey();
 
226
                        // System.out.println("Painting state " + activeState + "[curr is "
 
227
                        // + currState + "] with " + activeEntry.getValue());
 
228
                        if (activeState == currState)
 
229
                                continue;
 
230
 
 
231
                        float stateContribution = activeEntry.getValue().getContribution();
 
232
                        if (stateContribution > 0.0f) {
 
233
                                g2d.setComposite(AlphaComposite.SrcOver
 
234
                                                .derive(stateContribution));
 
235
                                SubstanceColorScheme fillColorScheme = SubstanceColorSchemeUtilities
 
236
                                                .getColorScheme(button,
 
237
                                                                ColorSchemeAssociationKind.FILL, activeState);
 
238
                                SubstanceColorScheme markColorScheme = SubstanceColorSchemeUtilities
 
239
                                                .getColorScheme(button,
 
240
                                                                ColorSchemeAssociationKind.MARK, activeState);
 
241
                                SubstanceColorScheme borderColorScheme = SubstanceColorSchemeUtilities
 
242
                                                .getColorScheme(button,
 
243
                                                                ColorSchemeAssociationKind.BORDER, activeState);
 
244
 
 
245
                                HashMapKey keyLayer = SubstanceCoreUtilities.getHashKey(
 
246
                                                fontSize, checkMarkSize, fillPainter.getDisplayName(),
 
247
                                                borderPainter.getDisplayName(), fillColorScheme
 
248
                                                                .getDisplayName(), markColorScheme
 
249
                                                                .getDisplayName(), borderColorScheme
 
250
                                                                .getDisplayName(), visibility);
 
251
                                Icon iconLayer = icons.get(keyLayer);
 
252
                                if (iconLayer == null) {
 
253
                                        iconLayer = new ImageIcon(SubstanceImageCreator
 
254
                                                        .getRadioButton(button, fillPainter, borderPainter,
 
255
                                                                        checkMarkSize, currState, 0,
 
256
                                                                        fillColorScheme, markColorScheme,
 
257
                                                                        borderColorScheme, visibility));
 
258
                                        icons.put(keyLayer, iconLayer);
 
259
                                }
 
260
 
 
261
                                iconLayer.paintIcon(button, g2d, 0, 0);
 
262
                        }
 
263
                }
 
264
 
 
265
                g2d.dispose();
 
266
                return new ImageIcon(result);
 
267
        }
 
268
 
 
269
        /*
 
270
         * (non-Javadoc)
 
271
         * 
 
272
         * @see javax.swing.plaf.ComponentUI#createUI(javax.swing.JComponent)
 
273
         */
 
274
        public static ComponentUI createUI(JComponent comp) {
 
275
                SubstanceCoreUtilities.testComponentCreationThreadingViolation(comp);
 
276
                return new SubstanceRadioButtonUI((JToggleButton) comp);
 
277
        }
 
278
 
 
279
        /**
 
280
         * Simple constructor.
 
281
         * 
 
282
         * @param button
 
283
         *            Associated radio button.
 
284
         */
 
285
        public SubstanceRadioButtonUI(JToggleButton button) {
 
286
                this.button = button;
 
287
                button.setRolloverEnabled(true);
 
288
                this.stateTransitionTracker = new StateTransitionTracker(this.button,
 
289
                                this.button.getModel());
 
290
        }
 
291
 
 
292
        /*
 
293
         * (non-Javadoc)
 
294
         * 
 
295
         * @see
 
296
         * javax.swing.plaf.basic.BasicButtonUI#createButtonListener(javax.swing
 
297
         * .AbstractButton)
 
298
         */
 
299
        @Override
 
300
        protected BasicButtonListener createButtonListener(AbstractButton b) {
 
301
                return new RolloverButtonListener(b, this.stateTransitionTracker);
 
302
        }
 
303
 
 
304
        /*
 
305
         * (non-Javadoc)
 
306
         * 
 
307
         * @see javax.swing.plaf.basic.BasicRadioButtonUI#getDefaultIcon()
 
308
         */
 
309
        @Override
 
310
        public Icon getDefaultIcon() {
 
311
                return SubstanceRadioButtonUI.getIcon(button,
 
312
                                this.stateTransitionTracker);
 
313
        }
 
314
 
 
315
        @Override
 
316
        public void paint(Graphics g, JComponent c) {
 
317
                AbstractButton b = (AbstractButton) c;
 
318
 
 
319
                // boolean isOpaque = b.isOpaque();
 
320
                // b.putClientProperty(SubstanceButtonUI.LOCK_OPACITY, Boolean.TRUE);
 
321
                // b.setOpaque(false);
 
322
 
 
323
                if (SubstanceCoreUtilities.isOpaque(c)) {
 
324
                        BackgroundPaintingUtils.update(g, c, false);
 
325
                }
 
326
 
 
327
                // b.setOpaque(isOpaque);
 
328
 
 
329
                // b.putClientProperty(SubstanceButtonUI.LOCK_OPACITY, null);
 
330
 
 
331
                FontMetrics fm = g.getFontMetrics();
 
332
 
 
333
                Insets i = b.getInsets();
 
334
 
 
335
                viewRect.x = i.left;
 
336
                viewRect.y = i.top;
 
337
                viewRect.width = b.getWidth() - (i.right + viewRect.x);
 
338
                viewRect.height = b.getHeight() - (i.bottom + viewRect.y);
 
339
 
 
340
                textRect.x = textRect.y = textRect.width = textRect.height = 0;
 
341
                iconRect.x = iconRect.y = iconRect.width = iconRect.height = 0;
 
342
 
 
343
                Font f = b.getFont();
 
344
                g.setFont(f);
 
345
 
 
346
                Icon icon = SubstanceCoreUtilities.getOriginalIcon(b, getDefaultIcon());
 
347
 
 
348
                // layout the text and icon
 
349
                String text = SwingUtilities.layoutCompoundLabel(c, fm, b.getText(),
 
350
                                icon, b.getVerticalAlignment(), b.getHorizontalAlignment(), b
 
351
                                                .getVerticalTextPosition(), b
 
352
                                                .getHorizontalTextPosition(), viewRect, iconRect,
 
353
                                textRect, b.getText() == null ? 0 : b.getIconTextGap());
 
354
 
 
355
                Graphics2D g2d = (Graphics2D) g.create();
 
356
                if (text != null && !text.equals("")) {
 
357
                        final View v = (View) b.getClientProperty(BasicHTML.propertyKey);
 
358
                        if (v != null) {
 
359
                                v.paint(g2d, textRect);
 
360
                        } else {
 
361
                                this.paintButtonText(g2d, b, textRect, text);
 
362
                        }
 
363
                }
 
364
 
 
365
                // Paint the Icon
 
366
                if (icon != null) {
 
367
                        icon.paintIcon(c, g2d, iconRect.x, iconRect.y);
 
368
                }
 
369
 
 
370
                if (b.isFocusPainted()) {
 
371
                        // make sure that the focus ring is not clipped
 
372
                        int focusRingPadding = SubstanceSizeUtils
 
373
                                        .getFocusRingPadding(SubstanceSizeUtils
 
374
                                                        .getComponentFontSize(button)) / 2;
 
375
                        SubstanceCoreUtilities.paintFocus(g2d, button, button, this, null,
 
376
                                        textRect, 1.0f, focusRingPadding);
 
377
                }
 
378
                // g2d.setColor(Color.red);
 
379
                // g2d.draw(iconRect);
 
380
                // g2d.draw(viewRect);
 
381
                // g2d.draw(textRect);
 
382
                // g2d.setColor(Color.blue);
 
383
                // g2d.drawRect(0, 0, button.getWidth() - 1, button.getHeight() - 1);
 
384
 
 
385
                g2d.dispose();
 
386
        }
 
387
 
 
388
        /**
 
389
         * Returns memory usage string.
 
390
         * 
 
391
         * @return Memory usage string.
 
392
         */
 
393
        public static String getMemoryUsage() {
 
394
                StringBuffer sb = new StringBuffer();
 
395
                sb.append("SubstanceRadioButtonUI: \n");
 
396
                sb.append("\t" + SubstanceRadioButtonUI.icons.size() + " icons");
 
397
                return sb.toString();
 
398
        }
 
399
 
 
400
        /**
 
401
         * Paints the text.
 
402
         * 
 
403
         * @param g
 
404
         *            Graphic context
 
405
         * @param button
 
406
         *            Button
 
407
         * @param textRect
 
408
         *            Text rectangle
 
409
         * @param text
 
410
         *            Text to paint
 
411
         */
 
412
        protected void paintButtonText(Graphics g, AbstractButton button,
 
413
                        Rectangle textRect, String text) {
 
414
                SubstanceTextUtilities.paintText(g, button, textRect, text, button
 
415
                                .getDisplayedMnemonicIndex());
 
416
        }
 
417
 
 
418
        @Override
 
419
        public boolean isInside(MouseEvent me) {
 
420
                return true;
 
421
        }
 
422
 
 
423
        @Override
 
424
        public StateTransitionTracker getTransitionTracker() {
 
425
                return this.stateTransitionTracker;
 
426
        }
 
427
}