1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package net.curre.prefcount.gui;
16
17 import java.awt.*;
18 import java.awt.event.ActionEvent;
19 import java.awt.event.ActionListener;
20 import java.awt.image.BufferedImage;
21 import javax.swing.*;
22 import javax.swing.border.LineBorder;
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 public class JFrameWithAnimatedInnerPanel extends JFrame {
40
41
42 public static final float ANIMATION_DURATION = 1000f;
43
44
45 public static final int ANIMATION_SLEEP = 50;
46
47
48 private static enum AnimationMode {
49
50 ROLLING_OUT, ROLLING_IN
51 }
52
53
54 private AnimationMode animationMode;
55
56
57 private JComponent sheet;
58
59
60 private JPanel glass;
61
62
63 private JFrameWithAnimatedInnerPanel.AnimatedInnerPanel animatedPanel;
64
65
66 private boolean animating;
67
68
69 private Timer animationTimer;
70
71
72 private long animationStart;
73
74
75 private boolean isOpen = false;
76
77
78
79
80
81
82 public JFrameWithAnimatedInnerPanel(String name) {
83 super(name);
84 }
85
86
87
88
89
90
91
92
93 public JDialog openAnimatedInnerPanel(JOptionPane dialogPane) {
94 if (!askPermissionToOpenOrClose(true)) {
95 return null;
96 }
97 super.setResizable(false);
98 JDialog dialog = dialogPane.createDialog(this, "dialog");
99 glass = (JPanel) getGlassPane();
100 glass.setLayout(new GridBagLayout());
101 animatedPanel = new JFrameWithAnimatedInnerPanel.AnimatedInnerPanel();
102 animatedPanel.setBorder(new LineBorder(Color.black, 1));
103
104 sheet = (JComponent) dialog.getContentPane();
105 sheet.setBorder(new LineBorder(Color.black, 1));
106 glass.removeAll();
107 animationMode = AnimationMode.ROLLING_OUT;
108 startAnimation();
109 return dialog;
110 }
111
112
113 public void closeAnimatedInnerPanel() {
114 if (askPermissionToOpenOrClose(false)) {
115 animationMode = AnimationMode.ROLLING_IN;
116 startAnimation();
117 super.setResizable(true);
118 isOpen = false;
119 }
120 }
121
122
123
124
125 private class AnimatedInnerPanel extends JPanel {
126
127 Dimension animatingSize = new Dimension(0, 1);
128 JComponent source;
129 BufferedImage offScreenImage;
130
131
132 public AnimatedInnerPanel() {
133 super();
134 setOpaque(true);
135 }
136
137
138
139
140
141
142 public void setSource(JComponent source) {
143 this.source = source;
144 animatingSize.width = source.getWidth();
145 GraphicsConfiguration gfxConfig =
146 GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
147 offScreenImage = gfxConfig.createCompatibleImage(source.getWidth(), source.getHeight());
148 Graphics2D offscreenGraphics = (Graphics2D) offScreenImage.getGraphics();
149 source.paint(offscreenGraphics);
150 }
151
152
153
154
155
156
157 public void setAnimatingHeight(int height) {
158 animatingSize.height = height;
159 setSize(animatingSize);
160 }
161
162
163 public Dimension getPreferredSize() {
164 return animatingSize;
165 }
166
167
168 public Dimension getMinimumSize() {
169 return animatingSize;
170 }
171
172
173 public Dimension getMaximumSize() {
174 return animatingSize;
175 }
176
177
178 public void paint(Graphics g) {
179
180
181 BufferedImage frgm = offScreenImage.getSubimage(0, offScreenImage.getHeight() - animatingSize.height,
182 source.getWidth(), animatingSize.height);
183 g.drawImage(frgm, 0, 0, this);
184 }
185 }
186
187
188 private class SomeActionListener implements ActionListener {
189
190
191 public void actionPerformed(ActionEvent actionEvent) {
192 if (animating) {
193
194 float animationPercent =
195 (System.currentTimeMillis() - animationStart) / ANIMATION_DURATION;
196 animationPercent = Math.min(1.0f, animationPercent);
197 int animatingHeight;
198 if (animationMode == AnimationMode.ROLLING_OUT) {
199 animatingHeight =
200 (int) (animationPercent * sheet.getHeight());
201 } else {
202 animatingHeight =
203 (int) ((1.0f - animationPercent) * sheet.getHeight());
204 }
205
206 animatedPanel.setAnimatingHeight(animatingHeight);
207 animatedPanel.repaint();
208 if (animationPercent >= 1.0f) {
209 stopAnimation();
210 if (animationMode == AnimationMode.ROLLING_OUT) {
211
212 finishShowingSheet();
213 } else {
214
215 glass.removeAll();
216 glass.setVisible(false);
217 }
218 }
219 }
220 }
221 }
222
223
224
225
226
227
228
229 private synchronized boolean askPermissionToOpenOrClose(boolean isToOpen) {
230 if (isToOpen) {
231 if (isOpen) {
232 return false;
233 } else {
234 isOpen = true;
235 return true;
236 }
237 } else {
238 return isOpen;
239 }
240 }
241
242
243 private void startAnimation() {
244 glass.repaint();
245
246 animatedPanel.setSource(sheet);
247 glass.removeAll();
248 GridBagConstraints gbc = new GridBagConstraints();
249 gbc.anchor = GridBagConstraints.NORTH;
250 glass.add(animatedPanel, gbc);
251 gbc.gridy = 1;
252 gbc.weighty = Integer.MAX_VALUE;
253 glass.add(Box.createGlue(), gbc);
254 glass.setVisible(true);
255
256
257 animationStart = System.currentTimeMillis();
258 if (animationTimer == null) {
259 animationTimer = new Timer(ANIMATION_SLEEP, new JFrameWithAnimatedInnerPanel.SomeActionListener());
260 }
261 animating = true;
262 animationTimer.start();
263 }
264
265
266 private void stopAnimation() {
267 animationTimer.stop();
268 animating = false;
269 }
270
271
272 private void finishShowingSheet() {
273 glass.removeAll();
274 GridBagConstraints gbc = new GridBagConstraints();
275 gbc.anchor = GridBagConstraints.NORTH;
276 glass.add(sheet, gbc);
277 gbc.gridy = 1;
278 gbc.weighty = Integer.MAX_VALUE;
279 glass.add(Box.createGlue(), gbc);
280
281 glass.revalidate();
282 glass.repaint();
283 }
284
285 }