1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.jdesktop.swingx.border;
23
24 import java.awt.Color;
25 import java.awt.Component;
26 import java.awt.Graphics;
27 import java.awt.Graphics2D;
28 import java.awt.Insets;
29 import java.awt.Point;
30 import java.awt.Rectangle;
31 import java.awt.RenderingHints;
32 import java.awt.geom.RoundRectangle2D;
33 import java.awt.image.BufferedImage;
34 import java.awt.image.ConvolveOp;
35 import java.awt.image.Kernel;
36 import java.util.HashMap;
37 import java.util.Map;
38
39 import javax.swing.UIManager;
40 import javax.swing.border.Border;
41
42
43
44
45
46
47
48
49
50 public class DropShadowBorder implements Border {
51 private static enum Position {TOP, TOP_LEFT, LEFT, BOTTOM_LEFT,
52 BOTTOM, BOTTOM_RIGHT, RIGHT, TOP_RIGHT}
53
54 private static final Map<Integer,Map<Position,BufferedImage>> CACHE
55 = new HashMap<Integer,Map<Position,BufferedImage>>();
56
57 private final Color lineColor;
58 private final int lineWidth;
59 private final int shadowSize;
60 private final float shadowOpacity;
61 private final int cornerSize;
62 private final boolean showTopShadow;
63 private final boolean showLeftShadow;
64 private final boolean showBottomShadow;
65 private final boolean showRightShadow;
66
67 public DropShadowBorder() {
68 this(UIManager.getColor("Control"), 1, 5);
69 }
70
71 public DropShadowBorder(Color lineColor, int lineWidth, int shadowSize) {
72 this(lineColor, lineWidth, shadowSize, .5f, 12, false, false, true, true);
73 }
74
75 public DropShadowBorder(Color lineColor, int lineWidth, boolean showLeftShadow) {
76 this(lineColor, lineWidth, 5, .5f, 12, false, showLeftShadow, true, true);
77 }
78
79 public DropShadowBorder(Color lineColor, int lineWidth, int shadowSize,
80 float shadowOpacity, int cornerSize, boolean showTopShadow,
81 boolean showLeftShadow, boolean showBottomShadow, boolean showRightShadow) {
82 this.lineColor = lineColor;
83 this.lineWidth = lineWidth;
84 this.shadowSize = shadowSize;
85 this.shadowOpacity = shadowOpacity;
86 this.cornerSize = cornerSize;
87 this.showTopShadow = showTopShadow;
88 this.showLeftShadow = showLeftShadow;
89 this.showBottomShadow = showBottomShadow;
90 this.showRightShadow = showRightShadow;
91 }
92
93
94
95
96 public void paintBorder(Component c, Graphics graphics, int x, int y, int width, int height) {
97
98
99
100
101 Map<Position,BufferedImage> images = getImages(null);
102
103
104
105
106
107
108
109 Graphics2D g2 = (Graphics2D)graphics.create();
110 g2.setColor(lineColor);
111
112
113
114
115
116
117
118
119 Point topLeftShadowPoint = null;
120 if (showLeftShadow || showTopShadow) {
121 topLeftShadowPoint = new Point();
122 if (showLeftShadow && !showTopShadow) {
123 topLeftShadowPoint.setLocation(x, y + shadowSize);
124 } else if (showLeftShadow && showTopShadow) {
125 topLeftShadowPoint.setLocation(x, y);
126 } else if (!showLeftShadow && showTopShadow) {
127 topLeftShadowPoint.setLocation(x + shadowSize, y);
128 }
129 }
130
131 Point bottomLeftShadowPoint = null;
132 if (showLeftShadow || showBottomShadow) {
133 bottomLeftShadowPoint = new Point();
134 if (showLeftShadow && !showBottomShadow) {
135 bottomLeftShadowPoint.setLocation(x, y + height - shadowSize - shadowSize);
136 } else if (showLeftShadow && showBottomShadow) {
137 bottomLeftShadowPoint.setLocation(x, y + height - shadowSize);
138 } else if (!showLeftShadow && showBottomShadow) {
139 bottomLeftShadowPoint.setLocation(x + shadowSize, y + height - shadowSize);
140 }
141 }
142
143 Point bottomRightShadowPoint = null;
144 if (showRightShadow || showBottomShadow) {
145 bottomRightShadowPoint = new Point();
146 if (showRightShadow && !showBottomShadow) {
147 bottomRightShadowPoint.setLocation(x + width - shadowSize, y + height - shadowSize - shadowSize);
148 } else if (showRightShadow && showBottomShadow) {
149 bottomRightShadowPoint.setLocation(x + width - shadowSize, y + height - shadowSize);
150 } else if (!showRightShadow && showBottomShadow) {
151 bottomRightShadowPoint.setLocation(x + width - shadowSize - shadowSize, y + height - shadowSize);
152 }
153 }
154
155 Point topRightShadowPoint = null;
156 if (showRightShadow || showTopShadow) {
157 topRightShadowPoint = new Point();
158 if (showRightShadow && !showTopShadow) {
159 topRightShadowPoint.setLocation(x + width - shadowSize, y + shadowSize);
160 } else if (showRightShadow && showTopShadow) {
161 topRightShadowPoint.setLocation(x + width - shadowSize, y);
162 } else if (!showRightShadow && showTopShadow) {
163 topRightShadowPoint.setLocation(x + width - shadowSize - shadowSize, y);
164 }
165 }
166
167 g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
168 RenderingHints.VALUE_INTERPOLATION_BILINEAR);
169
170 if (showLeftShadow) {
171 Rectangle leftShadowRect =
172 new Rectangle(x,
173 topLeftShadowPoint.y + shadowSize,
174 shadowSize,
175 bottomLeftShadowPoint.y - topLeftShadowPoint.y - shadowSize);
176 g2.drawImage(images.get(Position.LEFT),
177 leftShadowRect.x, leftShadowRect.y,
178 leftShadowRect.width, leftShadowRect.height, null);
179 }
180
181 if (showBottomShadow) {
182 Rectangle bottomShadowRect =
183 new Rectangle(bottomLeftShadowPoint.x + shadowSize,
184 y + height - shadowSize,
185 bottomRightShadowPoint.x - bottomLeftShadowPoint.x - shadowSize,
186 shadowSize);
187 g2.drawImage(images.get(Position.BOTTOM),
188 bottomShadowRect.x, bottomShadowRect.y,
189 bottomShadowRect.width, bottomShadowRect.height, null);
190 }
191
192 if (showRightShadow) {
193 Rectangle rightShadowRect =
194 new Rectangle(x + width - shadowSize,
195 topRightShadowPoint.y + shadowSize,
196 shadowSize,
197 bottomRightShadowPoint.y - topRightShadowPoint.y - shadowSize);
198 g2.drawImage(images.get(Position.RIGHT),
199 rightShadowRect.x, rightShadowRect.y,
200 rightShadowRect.width, rightShadowRect.height, null);
201 }
202
203 if (showTopShadow) {
204 Rectangle topShadowRect =
205 new Rectangle(topLeftShadowPoint.x + shadowSize,
206 y,
207 topRightShadowPoint.x - topLeftShadowPoint.x - shadowSize,
208 shadowSize);
209 g2.drawImage(images.get(Position.TOP),
210 topShadowRect.x, topShadowRect.y,
211 topShadowRect.width, topShadowRect.height, null);
212 }
213
214 if (showLeftShadow || showTopShadow) {
215 g2.drawImage(images.get(Position.TOP_LEFT),
216 topLeftShadowPoint.x, topLeftShadowPoint.y, null);
217 }
218 if (showLeftShadow || showBottomShadow) {
219 g2.drawImage(images.get(Position.BOTTOM_LEFT),
220 bottomLeftShadowPoint.x, bottomLeftShadowPoint.y, null);
221 }
222 if (showRightShadow || showBottomShadow) {
223 g2.drawImage(images.get(Position.BOTTOM_RIGHT),
224 bottomRightShadowPoint.x, bottomRightShadowPoint.y, null);
225 }
226 if (showRightShadow || showTopShadow) {
227 g2.drawImage(images.get(Position.TOP_RIGHT),
228 topRightShadowPoint.x, topRightShadowPoint.y, null);
229 }
230
231 g2.dispose();
232 }
233
234 private Map<Position,BufferedImage> getImages(Graphics2D g2) {
235
236
237 Map<Position,BufferedImage> images = CACHE.get(shadowSize);
238 if (images == null) {
239 images = new HashMap<Position,BufferedImage>();
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255 int rectWidth = cornerSize + 1;
256 RoundRectangle2D rect = new RoundRectangle2D.Double(0, 0, rectWidth, rectWidth, cornerSize, cornerSize);
257 int imageWidth = rectWidth + shadowSize * 2;
258 BufferedImage image = new BufferedImage(imageWidth, imageWidth, BufferedImage.TYPE_INT_ARGB);
259 Graphics2D buffer = (Graphics2D)image.getGraphics();
260 buffer.setColor(new Color(0.0f, 0.0f, 0.0f, shadowOpacity));
261 buffer.translate(shadowSize, shadowSize);
262 buffer.fill(rect);
263 buffer.dispose();
264
265 float blurry = 1.0f / (float)(shadowSize * shadowSize);
266 float[] blurKernel = new float[shadowSize * shadowSize];
267 for (int i=0; i<blurKernel.length; i++) {
268 blurKernel[i] = blurry;
269 }
270 ConvolveOp blur = new ConvolveOp(new Kernel(shadowSize, shadowSize, blurKernel));
271 BufferedImage targetImage = new BufferedImage(imageWidth, imageWidth, BufferedImage.TYPE_INT_ARGB);
272 ((Graphics2D)targetImage.getGraphics()).drawImage(image, blur, -(shadowSize/2), -(shadowSize/2));
273
274 int x = 1;
275 int y = 1;
276 int w = shadowSize;
277 int h = shadowSize;
278 images.put(Position.TOP_LEFT, getSubImage(targetImage, x, y, w, h));
279 x = 1;
280 y = h;
281 w = shadowSize;
282 h = 1;
283 images.put(Position.LEFT, getSubImage(targetImage, x, y, w, h));
284 x = 1;
285 y = rectWidth;
286 w = shadowSize;
287 h = shadowSize;
288 images.put(Position.BOTTOM_LEFT, getSubImage(targetImage, x, y, w, h));
289 x = cornerSize + 1;
290 y = rectWidth;
291 w = 1;
292 h = shadowSize;
293 images.put(Position.BOTTOM, getSubImage(targetImage, x, y, w, h));
294 x = rectWidth;
295 y = x;
296 w = shadowSize;
297 h = shadowSize;
298 images.put(Position.BOTTOM_RIGHT, getSubImage(targetImage, x, y, w, h));
299 x = rectWidth;
300 y = cornerSize + 1;
301 w = shadowSize;
302 h = 1;
303 images.put(Position.RIGHT, getSubImage(targetImage, x, y, w, h));
304 x = rectWidth;
305 y = 1;
306 w = shadowSize;
307 h = shadowSize;
308 images.put(Position.TOP_RIGHT, getSubImage(targetImage, x, y, w, h));
309 x = shadowSize;
310 y = 1;
311 w = 1;
312 h = shadowSize;
313 images.put(Position.TOP, getSubImage(targetImage, x, y, w, h));
314
315 image.flush();
316 }
317 return images;
318 }
319
320
321
322
323
324
325
326 private BufferedImage getSubImage(BufferedImage img,
327 int x, int y, int w, int h) {
328 BufferedImage ret = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
329 Graphics2D g2 = ret.createGraphics();
330 g2.drawImage(img,
331 0, 0, w, h,
332 x, y, x+w, y+h,
333 null);
334 g2.dispose();
335 return ret;
336 }
337
338
339
340
341 public Insets getBorderInsets(Component c) {
342 int top = showTopShadow ? lineWidth + shadowSize : lineWidth;
343 int left = showLeftShadow ? lineWidth + shadowSize : lineWidth;
344 int bottom = showBottomShadow ? lineWidth + shadowSize : lineWidth;
345 int right = showRightShadow ? lineWidth + shadowSize : lineWidth;
346 return new Insets(top, left, bottom, right);
347 }
348
349
350
351
352 public boolean isBorderOpaque() {
353 return false;
354 }
355
356 public boolean isShowTopShadow() {
357 return showTopShadow;
358 }
359
360 public boolean isShowLeftShadow() {
361 return showLeftShadow;
362 }
363
364 public boolean isShowRightShadow() {
365 return showRightShadow;
366 }
367
368 public boolean isShowBottomShadow() {
369 return showBottomShadow;
370 }
371
372 public int getLineWidth() {
373 return lineWidth;
374 }
375
376 public Color getLineColor() {
377 return lineColor;
378 }
379
380 public int getShadowSize() {
381 return shadowSize;
382 }
383
384 public float getShadowOpacity() {
385 return shadowOpacity;
386 }
387
388 public int getCornerSize() {
389 return cornerSize;
390 }
391 }