blob: 83e46b69b034e890aef1721a0a3db970e6a78e7a [file] [log] [blame]
/*
* Copyright (c) 2015 The Eclipse Foundation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Yatta Solutions - [466264] initial API and implementation
*/
package org.eclipse.oomph.setup.internal.installer;
import org.eclipse.oomph.internal.ui.ImageHoverButton;
import org.eclipse.oomph.ui.SpriteAnimator;
import org.eclipse.oomph.ui.UIUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
/**
* @author Andreas Scharf
*/
public class SimpleInstallLaunchButton extends ImageHoverButton
{
static final Color COLOR_INSTALL = SetupInstallerPlugin.getColor(250, 148, 0);
private static final Color COLOR_FOREGROUND_DEFAULT = AbstractSimpleDialog.COLOR_WHITE;
private static final Color COLOR_INSTALLING = SetupInstallerPlugin.getColor(50, 196, 0);
private static final Color COLOR_INSTALLING_FOREGROUND = AbstractSimpleDialog.COLOR_LABEL_FOREGROUND;
private static final Color COLOR_LAUNCH = COLOR_INSTALLING;
private static final long MINIMUM_PROGRESS_ANIMATION_DELAY = 20;
private static final long MAXIMUM_PROGRESS_ANIMATION_DELAY = 200;
private State currentState;
private float progress;
private ProgressSpinner progressSpinner;
public SimpleInstallLaunchButton(Composite parent)
{
super(parent, SWT.PUSH);
setForeground(UIUtil.getDisplay().getSystemColor(SWT.COLOR_WHITE));
setFont(SimpleInstallerDialog.getFont(5, "bold")); //$NON-NLS-1$
setCornerWidth(10);
setAlignment(SWT.CENTER);
setDisabledBackgroundColor(COLOR_DEFAULT_DISABLED_BACKGROUND);
setBackgroundMode(SWT.INHERIT_FORCE);
setLayout(null);
if (SimpleVariablePage.PROGRESS_WATCHDOG_TIMEOUT != 0)
{
progressSpinner = new ProgressSpinner(SetupInstallerPlugin.INSTANCE.getSWTImage("simple/progress_sprite.png"), 8, 4, 20); //$NON-NLS-1$
addControlListener(new ControlAdapter()
{
@Override
public void controlResized(ControlEvent e)
{
relocateProgressAnimation();
}
@Override
public void controlMoved(ControlEvent e)
{
relocateProgressAnimation();
}
});
// Skip first white image.
progressSpinner.setKeyframeRange(1, 31);
}
setCurrentState(State.INSTALL);
}
public float getProgress()
{
return progress;
}
public void setProgress(float progress)
{
if (progress < 0 || progress > 1)
{
throw new IllegalArgumentException(Messages.SimpleInstallLaunchButton_BadProgress_exception);
}
this.progress = progress;
redraw();
}
@Override
public boolean isHover()
{
// No hover during install.
return currentState == State.INSTALLING ? false : super.isHover();
}
public void setCurrentState(State newState)
{
if (newState == null)
{
throw new IllegalArgumentException(Messages.SimpleInstallLaunchButton_NullState_exception);
}
if (currentState != newState)
{
State oldState = currentState;
currentState = newState;
stateChanged(oldState, currentState);
}
}
private void stateChanged(State oldState, State newState)
{
setDefaultImage(newState.icon);
setHoverImage(newState.hoverIcon);
setDisabledImage(newState.disabledIcon);
setText(newState.label);
setToolTipText(newState.tooltip);
setBackground(newState.backgroundColor);
setForeground(newState.foregroundColor);
switch (newState)
{
case INSTALLING:
setListenersPaused(true);
setCursor(null);
setShowButtonDownState(false);
if (progressSpinner != null)
{
progressSpinner.setVisible(true);
}
break;
default:
setListenersPaused(false);
setCursor(UIUtil.getDisplay().getSystemCursor(SWT.CURSOR_HAND));
setShowButtonDownState(true);
stopProgressAnimation();
if (progressSpinner != null)
{
progressSpinner.setVisible(false);
}
}
}
public void setProgressAnimationSpeed(float speed)
{
if (progressSpinner != null)
{
if (speed < 0 || speed > 1)
{
throw new IllegalArgumentException(Messages.SimpleInstallLaunchButton_BadSpeed_exception);
}
int delay = Math.round((1f - speed) * MAXIMUM_PROGRESS_ANIMATION_DELAY);
progressSpinner.setDelay(Math.max(delay, MINIMUM_PROGRESS_ANIMATION_DELAY));
}
}
public void stopProgressAnimation()
{
if (progressSpinner != null)
{
progressSpinner.setVisible(false);
}
}
public void startProgressAnimation()
{
if (progressSpinner != null)
{
relocateProgressAnimation();
progressSpinner.setVisible(true);
}
}
private void relocateProgressAnimation()
{
if (progressSpinner != null)
{
GC gc = new GC(this);
try
{
Point textExtent = gc.textExtent(getText());
int spinnerTextGap = 10;
Rectangle clientArea = getClientArea();
int startX = (clientArea.width - textExtent.x) / 2 - spinnerTextGap - progressSpinner.getWidth();
int startY = (clientArea.height - progressSpinner.getHeight()) / 2;
progressSpinner.setLocation(startX, startY);
}
finally
{
gc.dispose();
}
}
}
public State getCurrentState()
{
return currentState;
}
@Override
public void drawBackground(GC gc, int x, int y, int width, int height, int offsetX, int offsetY)
{
if (currentState == State.INSTALLING)
{
gc.setBackground(AbstractSimpleDialog.COLOR_LIGHTEST_GRAY);
gc.fillRoundRectangle(x, y, width, height, getCornerWidth(), getCornerWidth());
int progressWidth = (int)(width * progress);
gc.setBackground(currentState.backgroundColor);
gc.fillRoundRectangle(x, y, progressWidth, height, getCornerWidth(), getCornerWidth());
// Check if we should draw a hard edge.
if (progressWidth <= width - getCornerWidth() / 2)
{
gc.fillRectangle(progressWidth - getCornerWidth(), y, getCornerWidth(), height);
}
if (progressSpinner != null)
{
progressSpinner.update(gc);
}
}
else
{
super.drawBackground(gc, x, y, width, height, offsetX, offsetY);
}
}
/**
* @author Andreas Scharf
*/
public static enum State
{
INSTALL(Messages.SimpleInstallLaunchButton_Install_label, Messages.SimpleInstallLaunchButton_Install_message, COLOR_INSTALL, COLOR_FOREGROUND_DEFAULT,
SetupInstallerPlugin.INSTANCE.getSWTImage("simple/install_button_install.png"), //$NON-NLS-1$
SetupInstallerPlugin.INSTANCE.getSWTImage("simple/install_button_install_hover.png"), //$NON-NLS-1$
SetupInstallerPlugin.INSTANCE.getSWTImage("simple/install_button_install_disabled.png")), //$NON-NLS-1$
INSTALLING(Messages.SimpleInstallLaunchButton_Installing_label, Messages.SimpleInstallLaunchButton_Installing_message, COLOR_INSTALLING,
COLOR_INSTALLING_FOREGROUND, null, null, null),
LAUNCH(Messages.SimpleInstallLaunchButton_Launch_label, Messages.SimpleInstallLaunchButton_Launch_message, COLOR_LAUNCH, COLOR_FOREGROUND_DEFAULT,
SetupInstallerPlugin.INSTANCE.getSWTImage("simple/install_button_launch.png"), //$NON-NLS-1$
SetupInstallerPlugin.INSTANCE.getSWTImage("simple/install_button_launch_hover.png"), null); //$NON-NLS-1$
public final Image icon;
public final Image hoverIcon;
public final Image disabledIcon;
public final String label;
public final String tooltip;
public final Color backgroundColor;
public final Color foregroundColor;
State(final String label, final String tooltip, final Color backgroundColor, final Color foregroundColor, final Image icon, final Image hoverIcon,
Image disabledIcon)
{
this.label = label;
this.tooltip = tooltip;
this.backgroundColor = backgroundColor;
this.foregroundColor = foregroundColor;
this.icon = icon;
this.hoverIcon = hoverIcon;
this.disabledIcon = disabledIcon;
}
}
/**
* Simple animation of progress. In contrast to {@link SpriteAnimator}, this spinner is
* not a SWT component, which eases handling of transparency on different platforms.
*
* @author Andreas Scharf
*/
private class ProgressSpinner implements Runnable
{
private Image[] sprites;
private int currentSpriteIndex = 0;
private long nextKeyframeTime = -1;
private boolean visible;
private long delay;
private int x = -1;
private int y = -1;
private int firstKeyframe = -1;
private int lastKeyframe = -1;
public ProgressSpinner(Image textureAtlas, int countX, int countY, long delay)
{
this.delay = delay;
sprites = UIUtil.extractSprites(textureAtlas, countX, countY);
firstKeyframe = 0;
lastKeyframe = sprites.length - 1;
visible = false;
}
public void setLocation(int x, int y)
{
this.x = x;
this.y = y;
}
public void setKeyframeRange(int firstKeyframe, int lastKeyframe)
{
this.firstKeyframe = firstKeyframe;
this.lastKeyframe = lastKeyframe;
}
public int getWidth()
{
return sprites[0].getBounds().width;
}
public int getHeight()
{
return sprites[0].getBounds().height;
}
public void setDelay(long delay)
{
this.delay = delay;
}
public void setVisible(boolean visible)
{
this.visible = visible;
if (this.visible)
{
schedule();
}
}
public void update(GC gc)
{
if (!visible || x < 0 || y < 0)
{
return;
}
gc.drawImage(sprites[currentSpriteIndex], x, y);
long now = System.currentTimeMillis();
if (now >= nextKeyframeTime)
{
if (++currentSpriteIndex > lastKeyframe)
{
currentSpriteIndex = firstKeyframe;
}
nextKeyframeTime = now + delay;
}
}
@Override
public void run()
{
if (visible && !isDisposed())
{
SimpleInstallLaunchButton.this.redraw();
schedule();
}
}
private void schedule()
{
getDisplay().timerExec((int)delay, this);
}
}
}