KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > RectangleAnimation


1 /*******************************************************************************
2  * Copyright (c) 2004, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.ui.internal;
12
13 import org.eclipse.core.runtime.IProgressMonitor;
14 import org.eclipse.core.runtime.IStatus;
15 import org.eclipse.core.runtime.Status;
16 import org.eclipse.core.runtime.jobs.Job;
17 import org.eclipse.jface.preference.IPreferenceStore;
18 import org.eclipse.jface.util.Geometry;
19 import org.eclipse.swt.graphics.GC;
20 import org.eclipse.swt.graphics.Image;
21 import org.eclipse.swt.graphics.Rectangle;
22 import org.eclipse.swt.widgets.Control;
23 import org.eclipse.swt.widgets.Display;
24 import org.eclipse.swt.widgets.Shell;
25 import org.eclipse.ui.IWorkbenchPreferenceConstants;
26 import org.eclipse.ui.internal.util.PrefUtil;
27
28 /**
29  * This job creates an animated rectangle that moves from a source rectangle to
30  * a target in a fixed amount of time. To begin the animation, instantiate this
31  * object then call schedule().
32  *
33  * @since 3.0
34  */

35 public class RectangleAnimation extends Job {
36     private static class AnimationFeedbackFactory {
37         /**
38          * Determines whether or not the system being used is
39          * sufficiently fast to support image animations.
40          *
41          * Assumes that a pixel is ~3 bytes
42          *
43          * For now we use a base limitation of 50MB/sec as a
44          * 'reverse blt' rate so that a 2MB size shell can be
45          * captured in under 1/25th of a sec.
46          */

47         private static final int IMAGE_ANIMATION_THRESHOLD = 25; // Frame captures / Sec
48
private static final int IMAGE_ANIMATION_TEST_LOOP_COUNT = 20; // test the copy 'n' times
49

50         //private static double framesPerSec = 0.0;
51

52         public static double getCaptureSpeed(Shell wb) {
53             // OK, capture
54
Rectangle bb = wb.getBounds();
55             Image backingStore = new Image(wb.getDisplay(), bb);
56             GC gc = new GC(wb);
57             
58             // Loop 'n' times to average the result
59
long startTime = System.currentTimeMillis();
60             for (int i = 0; i < IMAGE_ANIMATION_TEST_LOOP_COUNT; i++)
61                 gc.copyArea(backingStore, bb.x, bb.y);
62             gc.dispose();
63             long endTime = System.currentTimeMillis();
64             
65             // get Frames / Sec
66
double fps = IMAGE_ANIMATION_TEST_LOOP_COUNT / ((endTime-startTime) / 1000.0);
67             double pps = fps * (bb.width*bb.height*4); // 4 bytes/pixel
68
System.out.println("FPS: " + fps + " Bytes/sec: " + (long)pps); //$NON-NLS-1$ //$NON-NLS-2$
69
return fps;
70         }
71         
72         public boolean useImageAnimations(Shell wb) {
73             return getCaptureSpeed(wb) >= IMAGE_ANIMATION_THRESHOLD;
74         }
75         
76         public static DefaultAnimationFeedback createAnimationRenderer(Shell parentShell) {
77             // on the first call test the animation threshold to determine
78
// whether to use image animations or not...
79
// if (framesPerSec == 0.0)
80
// framesPerSec = getCaptureSpeed(parentShell);
81
//
82
// IPreferenceStore preferenceStore = PrefUtil.getAPIPreferenceStore();
83
// boolean useNewMinMax = preferenceStore.getBoolean(IWorkbenchPreferenceConstants.ENABLE_NEW_MIN_MAX);
84
//
85
// if (useNewMinMax && framesPerSec >= IMAGE_ANIMATION_THRESHOLD) {
86
// return new ImageAnimationFeedback();
87
// }
88
//
89
return new DefaultAnimationFeedback();
90         }
91     }
92     
93     // Constants
94
public static final int TICK_TIMER = 1;
95     public static final int FRAME_COUNT = 2;
96
97     // Animation Parameters
98
private Display display;
99     
100     private boolean enableAnimations;
101     private int timingStyle = TICK_TIMER;
102     private int duration;
103     
104     // Control State
105
private DefaultAnimationFeedback feedbackRenderer;
106     private long stepCount;
107     private long frameCount;
108     private long startTime;
109     private long curTime;
110     private long prevTime;
111     
112     // Macros
113
private boolean done() { return amount() >= 1.0; }
114
115     public static Rectangle interpolate(Rectangle start, Rectangle end,
116             double amount) {
117         double initialWeight = 1.0 - amount;
118
119         Rectangle result = new Rectangle((int) (start.x * initialWeight + end.x
120                 * amount), (int) (start.y * initialWeight + end.y * amount),
121                 (int) (start.width * initialWeight + end.width * amount),
122                 (int) (start.height * initialWeight + end.height * amount));
123
124         return result;
125     }
126     
127     // Animation Step
128
private Runnable JavaDoc animationStep = new Runnable JavaDoc() {
129
130         public void run() {
131             // Capture time
132
prevTime = curTime;
133             curTime = System.currentTimeMillis();
134
135             // Has the system timer 'ticked'?
136
if (curTime != prevTime) {
137                 clockTick();
138             }
139             
140             if (isUpdateStep()) {
141                 updateDisplay();
142                 frameCount++;
143             }
144             
145             stepCount++;
146         }
147
148     };
149     
150     /**
151      * Creates an animation that will morph the start rectangle to the end rectangle in the
152      * given number of milliseconds. The animation will take the given number of milliseconds to
153      * complete.
154      *
155      * Note that this is a Job, so you must invoke schedule() before the animation will begin
156      *
157      * @param whereToDraw specifies the composite where the animation will be drawn. Note that
158      * although the start and end rectangles can accept any value in display coordinates, the
159      * actual animation will be clipped to the boundaries of this composite. For this reason,
160      * it is good to select a composite that encloses both the start and end rectangles.
161      * @param start initial rectangle (display coordinates)
162      * @param end final rectangle (display coordinates)
163      * @param duration number of milliseconds over which the animation will run
164      */

165     public RectangleAnimation(Shell parentShell, Rectangle start,
166             Rectangle end, int duration) {
167         super(WorkbenchMessages.RectangleAnimation_Animating_Rectangle);
168
169         // if animations aren't on this is a NO-OP
170
IPreferenceStore preferenceStore = PrefUtil.getAPIPreferenceStore();
171         enableAnimations = preferenceStore.getBoolean(IWorkbenchPreferenceConstants.ENABLE_ANIMATIONS);
172         
173         if (!enableAnimations) {
174             return;
175         }
176
177         // Capture paraeters
178
display = parentShell.getDisplay();
179         this.duration = duration;
180
181         // Don't show the job in monitors
182
setSystem(true);
183         
184         // Pick the renderer (could be a preference...)
185
feedbackRenderer = AnimationFeedbackFactory.createAnimationRenderer(parentShell);
186         
187         // Set it up
188
feedbackRenderer.initialize(parentShell, start, end);
189         
190         // Set the animation's initial state
191
stepCount = 0;
192         //long totalFrames = (long) ((duration / 1000.0) * framesPerSec);
193
curTime = startTime = System.currentTimeMillis();
194     }
195
196     public RectangleAnimation(Shell parentShell, Rectangle start, Rectangle end) {
197         this(parentShell, start, end, 400);
198     }
199     
200     public void addStartRect(Rectangle rect) {
201         if (feedbackRenderer != null)
202             feedbackRenderer.addStartRect(rect);
203     }
204     
205     public void addEndRect(Rectangle rect) {
206         if (feedbackRenderer != null)
207             feedbackRenderer.addEndRect(rect);
208     }
209
210     public void addStartRect(Control ctrl) {
211         Rectangle ctrlBounds = ctrl.getBounds();
212         Rectangle startRect = Geometry.toDisplay(ctrl.getParent(), ctrlBounds);
213         addStartRect(startRect);
214     }
215
216     public void addEndRect(Control ctrl) {
217         Rectangle ctrlBounds = ctrl.getBounds();
218         Rectangle endRect = Geometry.toDisplay(ctrl.getParent(), ctrlBounds);
219         addEndRect(endRect);
220     }
221
222     /**
223      *
224      */

225     protected void clockTick() {
226     }
227     
228     /**
229      * @return
230      */

231     protected boolean isUpdateStep() {
232         switch (timingStyle) {
233             case TICK_TIMER:
234                 return prevTime != curTime;
235     
236             case FRAME_COUNT:
237                 return true;
238         }
239         
240         return false;
241     }
242
243     private double amount() {
244         double amount = 0.0;
245         
246         switch (timingStyle) {
247             case TICK_TIMER:
248                 amount = (double) (curTime - startTime) / (double) duration;
249                 break;
250     
251             case FRAME_COUNT:
252                 amount = (double)frameCount / (double)duration;
253         }
254         
255         if (amount > 1.0)
256             amount = 1.0;
257         
258         return amount;
259     }
260
261     /**
262      *
263      */

264     protected void updateDisplay() {
265         feedbackRenderer.renderStep(amount());
266     }
267
268     /* (non-Javadoc)
269      * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
270      */

271     protected IStatus run(IProgressMonitor monitor) {
272         
273         // We use preference value to indicate that the animation should be skipped on this platform.
274
if (!enableAnimations || feedbackRenderer == null) {
275             return Status.OK_STATUS;
276         }
277
278         // Do we have anything to animate ?
279
boolean isEmpty = feedbackRenderer.getStartRects().size() == 0;
280         if (isEmpty) {
281             return Status.OK_STATUS;
282         }
283         
284         // We're starting, initialize
285
display.syncExec(new Runnable JavaDoc() {
286             public void run() {
287                 feedbackRenderer.jobInit();
288             }
289         });
290         
291         // Only start the animation timer -after- we've initialized
292
curTime = startTime = System.currentTimeMillis();
293         
294         while (!done()) {
295             display.syncExec(animationStep);
296             // Don't pin the CPU
297
Thread.yield();
298         }
299
300         //System.out.println("Done: " + (curTime-startTime) + " steps: " + stepCount + " frames:" + frameCount); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
301
// We're done, clean up
302
display.syncExec(new Runnable JavaDoc() {
303             public void run() {
304                 feedbackRenderer.dispose();
305             }
306         });
307     
308         return Status.OK_STATUS;
309     }
310 }
311
Popular Tags