2
* Copyright (c) 2005-2010 Substance Kirill Grouchnikov. All Rights Reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions are met:
7
* o Redistributions of source code must retain the above copyright notice,
8
* this list of conditions and the following disclaimer.
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.
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.
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.
30
package org.pushingpixels.substance.internal.utils.border;
33
import java.awt.image.BufferedImage;
36
import javax.swing.JComponent;
37
import javax.swing.border.Border;
38
import javax.swing.plaf.ComponentUI;
39
import javax.swing.plaf.UIResource;
40
import javax.swing.text.JTextComponent;
42
import org.pushingpixels.substance.api.*;
43
import org.pushingpixels.substance.internal.animation.StateTransitionTracker;
44
import org.pushingpixels.substance.internal.animation.TransitionAwareUI;
45
import org.pushingpixels.substance.internal.utils.*;
48
* Text component border for the <b>Substance</b> look and feel.
50
* @author Kirill Grouchnikov
52
public class SubstanceTextComponentBorder implements Border, UIResource {
54
* Insets of <code>this</code> border.
56
protected Insets myInsets;
59
* Cache of small border images.
61
private static LazyResettableHashMap<BufferedImage> smallImageCache = new LazyResettableHashMap<BufferedImage>(
62
"SubstanceTextComponentBorder");
65
* Creates a new border with the specified insets.
70
public SubstanceTextComponentBorder(Insets insets) {
71
this.myInsets = new Insets(insets.top, insets.left, insets.bottom,
76
* Paints border instance for the specified component.
83
* Component left X (in graphics context).
85
* Component top Y (in graphics context).
91
* Component enabled status.
93
* Component focus ownership status.
95
private void paintBorder(JComponent c, Graphics g, int x, int y, int width,
96
int height, boolean isEnabled, boolean hasFocus) {
97
// failsafe for LAF change
98
if (!SubstanceLookAndFeel.isCurrentLookAndFeel()) {
102
if ((width <= 0) || (height <= 0))
105
Graphics2D graphics = (Graphics2D) g.create();
107
// float cyclePos = 1.0f;
109
float radius = 2.0f * SubstanceSizeUtils
110
.getClassicButtonCornerRadius(SubstanceSizeUtils
111
.getComponentFontSize(c));
113
JTextComponent componentForTransitions = SubstanceCoreUtilities
114
.getTextComponentForTransitions(c);
116
if (componentForTransitions != null) {
117
ComponentUI ui = componentForTransitions.getUI();
118
if (ui instanceof TransitionAwareUI) {
119
TransitionAwareUI trackable = (TransitionAwareUI) ui;
120
StateTransitionTracker stateTransitionTracker = trackable
121
.getTransitionTracker();
122
StateTransitionTracker.ModelStateInfo modelStateInfo = stateTransitionTracker
123
.getModelStateInfo();
124
Map<ComponentState, StateTransitionTracker.StateContributionInfo> activeStates = modelStateInfo
125
.getStateContributionMap();
126
ComponentState currState = modelStateInfo.getCurrModelState();
127
if (currState.isDisabled())
128
currState = ComponentState.DISABLED_SELECTED;
129
if (width * height < 100000) {
130
SubstanceColorScheme baseBorderScheme = SubstanceColorSchemeUtilities
131
.getColorScheme(componentForTransitions,
132
ColorSchemeAssociationKind.BORDER,
135
HashMapKey baseKey = SubstanceCoreUtilities.getHashKey(
136
SubstanceSizeUtils.getComponentFontSize(c), width,
137
height, radius, baseBorderScheme.getDisplayName());
138
BufferedImage baseLayer = smallImageCache.get(baseKey);
139
float baseAlpha = SubstanceColorSchemeUtilities.getAlpha(c,
142
if (baseLayer == null) {
143
baseLayer = SubstanceCoreUtilities.getBlankImage(width,
145
Graphics2D g2d = baseLayer.createGraphics();
146
SubstanceImageCreator.paintTextComponentBorder(c, g2d,
147
0, 0, width, height, radius, baseBorderScheme);
149
smallImageCache.put(baseKey, baseLayer);
152
graphics.setComposite(AlphaComposite.SrcOver
154
graphics.drawImage(baseLayer, x, y, null);
156
if (!currState.isDisabled() && (activeStates.size() > 1)) {
157
for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : activeStates
159
ComponentState activeState = activeEntry.getKey();
160
if (activeState == currState)
163
float contribution = activeEntry.getValue()
165
if (contribution == 0.0f)
168
SubstanceColorScheme borderScheme = SubstanceColorSchemeUtilities
169
.getColorScheme(componentForTransitions,
170
ColorSchemeAssociationKind.BORDER,
173
HashMapKey key = SubstanceCoreUtilities.getHashKey(
174
SubstanceSizeUtils.getComponentFontSize(c),
175
width, height, radius, borderScheme
177
BufferedImage layer = smallImageCache.get(key);
178
float alpha = SubstanceColorSchemeUtilities
179
.getAlpha(c, activeState);
182
layer = SubstanceCoreUtilities.getBlankImage(
184
Graphics2D g2d = layer.createGraphics();
185
SubstanceImageCreator.paintTextComponentBorder(
186
c, g2d, 0, 0, width, height, radius,
189
smallImageCache.put(key, layer);
192
graphics.setComposite(AlphaComposite.SrcOver
193
.derive(alpha * contribution));
194
graphics.drawImage(layer, x, y, null);
199
// for borders larger than 100000 pixels, use simple
201
graphics.translate(x, y);
203
SubstanceColorScheme baseBorderScheme = SubstanceColorSchemeUtilities
204
.getColorScheme(componentForTransitions,
205
ColorSchemeAssociationKind.BORDER,
207
float baseAlpha = SubstanceColorSchemeUtilities.getAlpha(c,
209
graphics.setComposite(AlphaComposite.SrcOver
211
SubstanceImageCreator.paintSimpleBorder(c, graphics, width,
212
height, baseBorderScheme);
214
if (!currState.isDisabled() && (activeStates.size() > 1)) {
215
for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : activeStates
217
ComponentState activeState = activeEntry.getKey();
218
if (activeState == currState)
221
float contribution = activeEntry.getValue()
223
if (contribution == 0.0f)
226
SubstanceColorScheme borderScheme = SubstanceColorSchemeUtilities
227
.getColorScheme(componentForTransitions,
228
ColorSchemeAssociationKind.BORDER,
230
float alpha = SubstanceColorSchemeUtilities
231
.getAlpha(c, activeState);
232
graphics.setComposite(AlphaComposite.SrcOver
233
.derive(alpha * contribution));
234
SubstanceImageCreator.paintSimpleBorder(c,
235
graphics, width, height, borderScheme);
241
ComponentState currState = isEnabled ? ComponentState.ENABLED
242
: ComponentState.DISABLED_UNSELECTED;
243
SubstanceColorScheme borderColorScheme = SubstanceColorSchemeUtilities
244
.getColorScheme(c, ColorSchemeAssociationKind.BORDER,
246
if (width * height < 100000) {
247
HashMapKey hashKey = SubstanceCoreUtilities.getHashKey(
248
SubstanceSizeUtils.getComponentFontSize(c), width,
249
height, radius, borderColorScheme.getDisplayName());
250
BufferedImage result = smallImageCache.get(hashKey);
251
if (result == null) {
252
result = SubstanceCoreUtilities
253
.getBlankImage(width, height);
254
Graphics2D g2d = result.createGraphics();
255
SubstanceImageCreator.paintTextComponentBorder(c, g2d, 0,
256
0, width, height, radius, borderColorScheme);
258
smallImageCache.put(hashKey, result);
260
graphics.drawImage(result, x, y, null);
262
// for borders larger than 100000 pixels, use simple
264
graphics.translate(x, y);
265
SubstanceImageCreator.paintSimpleBorder(c, graphics, width,
266
height, borderColorScheme);
276
* @see javax.swing.border.Border#paintBorder(java.awt.Component,
277
* java.awt.Graphics, int, int, int, int)
280
public void paintBorder(Component c, Graphics g, int x, int y, int width,
282
paintBorder((JComponent) c, g, x, y, width, height, c.isEnabled(), c
289
* @see javax.swing.border.Border#getBorderInsets(java.awt.Component)
292
public Insets getBorderInsets(Component c) {
293
return this.myInsets;
299
* @see javax.swing.border.Border#isBorderOpaque()
302
public boolean isBorderOpaque() {