1 /* |
|
2 * CDDL HEADER START |
|
3 * |
|
4 * The contents of this file are subject to the terms of the |
|
5 * Common Development and Distribution License (the "License"). |
|
6 * You may not use this file except in compliance with the License. |
|
7 * |
|
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
|
9 * or http://www.opensolaris.org/os/licensing. |
|
10 * See the License for the specific language governing permissions |
|
11 * and limitations under the License. |
|
12 * |
|
13 * When distributing Covered Code, include this CDDL HEADER in each |
|
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
|
15 * If applicable, add the following below this CDDL HEADER, with the |
|
16 * fields enclosed by brackets "[]" replaced with your own identifying |
|
17 * information: Portions Copyright [yyyy] [name of copyright owner] |
|
18 * |
|
19 * CDDL HEADER END |
|
20 */ |
|
21 |
|
22 /* |
|
23 * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. |
|
24 */ |
|
25 |
|
26 package com.oracle.solaris.vp.util.swing; |
|
27 |
|
28 import java.awt.*; |
|
29 import java.awt.event.*; |
|
30 import java.awt.image.BufferedImage; |
|
31 import javax.swing.*; |
|
32 import javax.swing.border.*; |
|
33 import org.jdesktop.animation.timing.*; |
|
34 |
|
35 @SuppressWarnings({"serial"}) |
|
36 public class FadablePanel extends JPanel implements TimingTarget { |
|
37 // |
|
38 // Instance data |
|
39 // |
|
40 |
|
41 private AlphaComposite composite; |
|
42 private BufferedImage image; |
|
43 private boolean useImageBuffer; |
|
44 |
|
45 private AnimatedBooleanProperty faded = |
|
46 new AnimatedBooleanProperty(500, this); |
|
47 |
|
48 private ShowingListener showListener = |
|
49 new ShowingListener() { |
|
50 @Override |
|
51 public void componentHidden() { |
|
52 setFaded(true, false); |
|
53 } |
|
54 |
|
55 public void componentShown() { |
|
56 setFaded(false); |
|
57 } |
|
58 }; |
|
59 |
|
60 // |
|
61 // Constructors |
|
62 // |
|
63 |
|
64 public FadablePanel(LayoutManager layout) { |
|
65 setLayout(layout == null ? new BorderLayout() : layout); |
|
66 setOpaque(false); |
|
67 } |
|
68 |
|
69 public FadablePanel() { |
|
70 this((LayoutManager)null); |
|
71 } |
|
72 |
|
73 public FadablePanel(JComponent c) { |
|
74 this(); |
|
75 add(c, BorderLayout.CENTER); |
|
76 } |
|
77 |
|
78 // |
|
79 // TimingTarget methods |
|
80 // |
|
81 |
|
82 @Override |
|
83 public void begin() { |
|
84 // No implementation here -- setup should occur before the animator is |
|
85 // started since the clock is ticking at this point. A design flaw in |
|
86 // the timing framework? Perhaps. |
|
87 } |
|
88 |
|
89 @Override |
|
90 public void end() { |
|
91 image = null; |
|
92 } |
|
93 |
|
94 @Override |
|
95 public void repeat() { |
|
96 } |
|
97 |
|
98 @Override |
|
99 public void timingEvent(float alpha) { |
|
100 setAlpha(1f - alpha); |
|
101 repaint(); |
|
102 } |
|
103 |
|
104 // |
|
105 // Component methods |
|
106 // |
|
107 |
|
108 @Override |
|
109 public void paint(Graphics g) { |
|
110 Composite composite = this.composite; |
|
111 if (composite == null) { |
|
112 super.paint(g); |
|
113 return; |
|
114 } |
|
115 |
|
116 Graphics2D g2 = (Graphics2D)g; |
|
117 Composite old = g2.getComposite(); |
|
118 g2.setComposite(composite); |
|
119 |
|
120 if (useImageBuffer) { |
|
121 if (image == null) { |
|
122 // We have just begun animating -- paint initially to an image |
|
123 image = new BufferedImage(getWidth(), getHeight(), |
|
124 BufferedImage.TYPE_INT_ARGB); |
|
125 Graphics2D iG = image.createGraphics(); |
|
126 super.paint(iG); |
|
127 } |
|
128 |
|
129 g2.drawImage(image, 0, 0, null); |
|
130 } else { |
|
131 super.paint(g2); |
|
132 } |
|
133 |
|
134 g2.setComposite(old); |
|
135 } |
|
136 |
|
137 // |
|
138 // FadablePanel methods |
|
139 // |
|
140 |
|
141 public float getAlpha() { |
|
142 return composite == null ? 1f : composite.getAlpha(); |
|
143 } |
|
144 |
|
145 public Animator getAnimator() { |
|
146 return faded.getAnimator(); |
|
147 } |
|
148 |
|
149 public boolean getUseImageBuffer() { |
|
150 return useImageBuffer; |
|
151 } |
|
152 |
|
153 public boolean isFaded() { |
|
154 return faded.getValue(); |
|
155 } |
|
156 |
|
157 public void setAlpha(float alpha) { |
|
158 this.composite = alpha == 1f ? null : AlphaComposite.getInstance( |
|
159 AlphaComposite.SRC_OVER, alpha); |
|
160 } |
|
161 |
|
162 public void setFaded(boolean value) { |
|
163 setFaded(value, isShowing()); |
|
164 } |
|
165 |
|
166 public void setFaded(boolean value, boolean animated) { |
|
167 faded.setValue(value, animated); |
|
168 } |
|
169 |
|
170 /** |
|
171 * Synchronizes the fade of this component with its visibility. When this |
|
172 * {@code FadePanel} becomes both visible and displayable, it fades in. |
|
173 * When this {@code FadePanel} loses either visibility or displayability, it |
|
174 * fades out. |
|
175 * <p> |
|
176 * This synchronization may facilitate using a {@code FadePanel} as a glass |
|
177 * pane. |
|
178 * |
|
179 * @param synch |
|
180 * {@code true} to establish this link, {@code false} to remove |
|
181 * this link if set up previously |
|
182 */ |
|
183 public void setSyncFadeWithVisibility(boolean synch) { |
|
184 if (synch) { |
|
185 // Make sure listener is only added once |
|
186 removeListener(); |
|
187 |
|
188 addHierarchyListener(showListener); |
|
189 showListener.updateShowing(this); |
|
190 } else { |
|
191 removeListener(); |
|
192 } |
|
193 } |
|
194 |
|
195 public void setUseImageBuffer(boolean useImageBuffer) { |
|
196 this.useImageBuffer = useImageBuffer; |
|
197 } |
|
198 |
|
199 // |
|
200 // Private methods |
|
201 // |
|
202 |
|
203 private void removeListener() { |
|
204 removeHierarchyListener(showListener); |
|
205 } |
|
206 |
|
207 // |
|
208 // Static methods |
|
209 // |
|
210 |
|
211 // XXX Unit test - remove |
|
212 public static void main(String args[]) { |
|
213 JButton b1 = new JButton("Hello"); |
|
214 JLabel b2 = new JLabel("There"); |
|
215 |
|
216 Border border = new CompoundBorder( |
|
217 new EmptyBorder(5, 5, 5, 5), |
|
218 new LineBorder(ColorUtil.getRandomColor(), 5)); |
|
219 |
|
220 JPanel p = new JPanel(new GridLayout()); |
|
221 p.setBackground(ColorUtil.getRandomColor()); |
|
222 p.setBorder(border); |
|
223 p.add(b1); |
|
224 p.add(b2); |
|
225 |
|
226 final FadablePanel fadePanel = new FadablePanel(p); |
|
227 fadePanel.setBorder(border); |
|
228 |
|
229 JButton fadeButton = new JButton("fade"); |
|
230 fadeButton.addActionListener( |
|
231 new ActionListener() { |
|
232 @Override |
|
233 public void actionPerformed(ActionEvent e) { |
|
234 boolean faded = fadePanel.isFaded(); |
|
235 fadePanel.setFaded(!faded); |
|
236 } |
|
237 }); |
|
238 |
|
239 JButton fadeNowButton = new JButton("fade immediately"); |
|
240 fadeNowButton.addActionListener( |
|
241 new ActionListener() { |
|
242 @Override |
|
243 public void actionPerformed(ActionEvent e) { |
|
244 boolean faded = fadePanel.isFaded(); |
|
245 fadePanel.setFaded(!faded, false); |
|
246 } |
|
247 }); |
|
248 |
|
249 JButton stopButton = new JButton("stop"); |
|
250 stopButton.addActionListener( |
|
251 new ActionListener() { |
|
252 @Override |
|
253 public void actionPerformed(ActionEvent e) { |
|
254 fadePanel.getAnimator().stop(); |
|
255 } |
|
256 }); |
|
257 |
|
258 JFrame frame = new JFrame(); |
|
259 Container c = frame.getContentPane(); |
|
260 c.setBackground(Color.red); |
|
261 c.setLayout(new GridLayout()); |
|
262 c.add(fadePanel); |
|
263 c.add(fadeButton); |
|
264 c.add(fadeNowButton); |
|
265 c.add(stopButton); |
|
266 frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); |
|
267 frame.pack(); |
|
268 Dimension d = frame.getSize(); |
|
269 frame.setSize(d.width * 2, d.height * 2); |
|
270 frame.setVisible(true); |
|
271 } |
|
272 } |
|