org.eclipse.ui.internal.RectangleAnimation Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of workbench Show documentation
Show all versions of workbench Show documentation
This plug-in contains the bulk of the Workbench implementation, and depends on JFace, SWT, and Core Runtime. It cannot be used independently from org.eclipse.ui. Workbench client plug-ins should not depend directly on this plug-in.
The newest version!
/*******************************************************************************
* Copyright (c) 2004, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.internal;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.util.Geometry;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchPreferenceConstants;
import org.eclipse.ui.internal.util.PrefUtil;
/**
* This job creates an animated rectangle that moves from a source rectangle to
* a target in a fixed amount of time. To begin the animation, instantiate this
* object then call schedule().
*
* @since 3.0
*/
public class RectangleAnimation extends Job {
private static class AnimationFeedbackFactory {
/**
* Determines whether or not the system being used is
* sufficiently fast to support image animations.
*
* Assumes that a pixel is ~3 bytes
*
* For now we use a base limitation of 50MB/sec as a
* 'reverse blt' rate so that a 2MB size shell can be
* captured in under 1/25th of a sec.
*/
private static final int IMAGE_ANIMATION_THRESHOLD = 25; // Frame captures / Sec
private static final int IMAGE_ANIMATION_TEST_LOOP_COUNT = 20; // test the copy 'n' times
//private static double framesPerSec = 0.0;
public static double getCaptureSpeed(Shell wb) {
// OK, capture
Rectangle bb = wb.getBounds();
Image backingStore = new Image(wb.getDisplay(), bb);
GC gc = new GC(wb);
// Loop 'n' times to average the result
long startTime = System.currentTimeMillis();
for (int i = 0; i < IMAGE_ANIMATION_TEST_LOOP_COUNT; i++)
gc.copyArea(backingStore, bb.x, bb.y);
gc.dispose();
long endTime = System.currentTimeMillis();
// get Frames / Sec
double fps = IMAGE_ANIMATION_TEST_LOOP_COUNT / ((endTime-startTime) / 1000.0);
double pps = fps * (bb.width*bb.height*4); // 4 bytes/pixel
System.out.println("FPS: " + fps + " Bytes/sec: " + (long)pps); //$NON-NLS-1$ //$NON-NLS-2$
return fps;
}
public boolean useImageAnimations(Shell wb) {
return getCaptureSpeed(wb) >= IMAGE_ANIMATION_THRESHOLD;
}
public static DefaultAnimationFeedback createAnimationRenderer(Shell parentShell) {
// on the first call test the animation threshold to determine
// whether to use image animations or not...
// if (framesPerSec == 0.0)
// framesPerSec = getCaptureSpeed(parentShell);
//
// IPreferenceStore preferenceStore = PrefUtil.getAPIPreferenceStore();
// boolean useNewMinMax = preferenceStore.getBoolean(IWorkbenchPreferenceConstants.ENABLE_NEW_MIN_MAX);
//
// if (useNewMinMax && framesPerSec >= IMAGE_ANIMATION_THRESHOLD) {
// return new ImageAnimationFeedback();
// }
//
return new DefaultAnimationFeedback();
}
}
// Constants
public static final int TICK_TIMER = 1;
public static final int FRAME_COUNT = 2;
// Animation Parameters
private Display display;
private boolean enableAnimations;
private int timingStyle = TICK_TIMER;
private int duration;
// Control State
private DefaultAnimationFeedback feedbackRenderer;
private long stepCount;
private long frameCount;
private long startTime;
private long curTime;
private long prevTime;
// Macros
private boolean done() { return amount() >= 1.0; }
public static Rectangle interpolate(Rectangle start, Rectangle end,
double amount) {
double initialWeight = 1.0 - amount;
Rectangle result = new Rectangle((int) (start.x * initialWeight + end.x
* amount), (int) (start.y * initialWeight + end.y * amount),
(int) (start.width * initialWeight + end.width * amount),
(int) (start.height * initialWeight + end.height * amount));
return result;
}
// Animation Step
private Runnable animationStep = new Runnable() {
public void run() {
// Capture time
prevTime = curTime;
curTime = System.currentTimeMillis();
// Has the system timer 'ticked'?
if (curTime != prevTime) {
clockTick();
}
if (isUpdateStep()) {
updateDisplay();
frameCount++;
}
stepCount++;
}
};
/**
* Creates an animation that will morph the start rectangle to the end rectangle in the
* given number of milliseconds. The animation will take the given number of milliseconds to
* complete.
*
* Note that this is a Job, so you must invoke schedule() before the animation will begin
*
* @param whereToDraw specifies the composite where the animation will be drawn. Note that
* although the start and end rectangles can accept any value in display coordinates, the
* actual animation will be clipped to the boundaries of this composite. For this reason,
* it is good to select a composite that encloses both the start and end rectangles.
* @param start initial rectangle (display coordinates)
* @param end final rectangle (display coordinates)
* @param duration number of milliseconds over which the animation will run
*/
public RectangleAnimation(Shell parentShell, Rectangle start,
Rectangle end, int duration) {
super(WorkbenchMessages.RectangleAnimation_Animating_Rectangle);
// if animations aren't on this is a NO-OP
IPreferenceStore preferenceStore = PrefUtil.getAPIPreferenceStore();
enableAnimations = preferenceStore.getBoolean(IWorkbenchPreferenceConstants.ENABLE_ANIMATIONS);
if (!enableAnimations) {
return;
}
// Capture paraeters
display = parentShell.getDisplay();
this.duration = duration;
// Don't show the job in monitors
setSystem(true);
// Pick the renderer (could be a preference...)
feedbackRenderer = AnimationFeedbackFactory.createAnimationRenderer(parentShell);
// Set it up
feedbackRenderer.initialize(parentShell, start, end);
// Set the animation's initial state
stepCount = 0;
//long totalFrames = (long) ((duration / 1000.0) * framesPerSec);
curTime = startTime = System.currentTimeMillis();
}
public RectangleAnimation(Shell parentShell, Rectangle start, Rectangle end) {
this(parentShell, start, end, 400);
}
public void addStartRect(Rectangle rect) {
if (feedbackRenderer != null)
feedbackRenderer.addStartRect(rect);
}
public void addEndRect(Rectangle rect) {
if (feedbackRenderer != null)
feedbackRenderer.addEndRect(rect);
}
public void addStartRect(Control ctrl) {
Rectangle ctrlBounds = ctrl.getBounds();
Rectangle startRect = Geometry.toDisplay(ctrl.getParent(), ctrlBounds);
addStartRect(startRect);
}
public void addEndRect(Control ctrl) {
Rectangle ctrlBounds = ctrl.getBounds();
Rectangle endRect = Geometry.toDisplay(ctrl.getParent(), ctrlBounds);
addEndRect(endRect);
}
/**
*
*/
protected void clockTick() {
}
/**
* @return
*/
protected boolean isUpdateStep() {
switch (timingStyle) {
case TICK_TIMER:
return prevTime != curTime;
case FRAME_COUNT:
return true;
}
return false;
}
private double amount() {
double amount = 0.0;
switch (timingStyle) {
case TICK_TIMER:
amount = (double) (curTime - startTime) / (double) duration;
break;
case FRAME_COUNT:
amount = (double)frameCount / (double)duration;
}
if (amount > 1.0)
amount = 1.0;
return amount;
}
/**
*
*/
protected void updateDisplay() {
feedbackRenderer.renderStep(amount());
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
*/
protected IStatus run(IProgressMonitor monitor) {
// We use preference value to indicate that the animation should be skipped on this platform.
if (!enableAnimations || feedbackRenderer == null) {
return Status.OK_STATUS;
}
// Do we have anything to animate ?
boolean isEmpty = feedbackRenderer.getStartRects().size() == 0;
if (isEmpty) {
return Status.OK_STATUS;
}
// We're starting, initialize
display.syncExec(new Runnable() {
public void run() {
feedbackRenderer.jobInit();
}
});
// Only start the animation timer -after- we've initialized
curTime = startTime = System.currentTimeMillis();
while (!done()) {
display.syncExec(animationStep);
// Don't pin the CPU
Thread.yield();
}
//System.out.println("Done: " + (curTime-startTime) + " steps: " + stepCount + " frames:" + frameCount); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
// We're done, clean up
display.syncExec(new Runnable() {
public void run() {
feedbackRenderer.dispose();
}
});
return Status.OK_STATUS;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy