/*******************************************************************************
* Copyright (c) 2011, 2012 Wind River Systems, Inc. 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:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.tcf.te.tcf.filesystem.ui.internal.decorators;
import org.eclipse.core.runtime.Assert;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.tcf.te.tcf.filesystem.ui.activator.UIPlugin;
import org.eclipse.tcf.te.ui.jface.images.AbstractImageDescriptor;
/**
* The descriptor for a phantom-like image.
*/
public class PhantomImageDescriptor extends AbstractImageDescriptor {
// The alpha data when highlight the base image.
private static final int HIGHLIGHT_ALPHA = 127;
// The key to store the cut mask image.
private static final String ID_FS_NODE_CUT_MASK = "FS_NODE_CUT_MASK@"; //$NON-NLS-1$
// The key to store the cut decoration image.
private static final String ID_FS_NODE_CUT = "FS_NODE_CUT@"; //$NON-NLS-1$
// the base image to decorate with overlays
private Image baseImage;
/**
* Constructor.
*/
public PhantomImageDescriptor(final Image baseImage) {
super(UIPlugin.getDefault().getImageRegistry());
this.baseImage = baseImage;
// build up the key for the image registry
String key = ID_FS_NODE_CUT + baseImage.hashCode();
setDecriptorKey(key);
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.resource.CompositeImageDescriptor#drawCompositeImage(int, int)
*/
@Override
protected void drawCompositeImage(int width, int height) {
drawCentered(baseImage, width, height);
drawCentered(getMaskImage(), width, height);
}
/**
* Get the mask image of the base image. The mask image is an image which
* has the data of the decorator image and the transparent mask of the
* base image. The decorator image (the key of which is CUT_DECORATOR_IMAGE)
* is a translucent white board, which will be drawn over the base image and
* make the base image sightly lighter. Try to the cut a file in a file explorer
* on Windows host, you'll see its icon is changed to a lighter version. The
* mask image created by this method will be drawn over the base image and
* generate the similar effect.
*
* @return The mask image used to decorate the base image.
*/
private Image getMaskImage() {
String maskKey = ID_FS_NODE_CUT_MASK + baseImage.hashCode();
Image maskImage = UIPlugin.getImage(maskKey);
if (maskImage == null) {
ImageData baseData = baseImage.getImageData();
PaletteData palette = new PaletteData(new RGB[]{new RGB(255, 255, 255), new RGB(0,0,0)});
ImageData imageData = new ImageData(baseData.width, baseData.height, 1, palette);
// Get the base image's transparency mask.
imageData.alphaData = createAlphaData();
maskImage = new Image(baseImage.getDevice(), imageData);
UIPlugin.getDefault().getImageRegistry().put(maskKey, maskImage);
}
return maskImage;
}
/**
* Create the alpha data that will be used in the mask image data.
*
* @return The alpha data.
*/
private byte[] createAlphaData() {
ImageData imageData = baseImage.getImageData();
if (imageData.maskData != null) {
if (imageData.depth == 32) {
return maskAlpha32();
}
return maskAlpha();
}
return nonMaskAlpha();
}
/**
* Create the alpha data for the base image that has no mask data.
*
* @return The alpha data.
*/
private byte[] nonMaskAlpha() {
ImageData imageData = baseImage.getImageData();
Assert.isTrue(imageData.maskData == null);
byte[] alphaData = new byte[imageData.width * imageData.height];
int i = 0;
for (int y = 0; y < imageData.height; y++) {
for (int x = 0; x < imageData.width; x++) {
int pixel = imageData.getPixel(x, y);
int alpha = 255;
if (imageData.transparentPixel != -1 && imageData.transparentPixel == pixel) {
// If it has a transparent pixel and the current pixel is the transparent.
alpha = 0;
}
else if (imageData.alpha != -1) {
// If it has a global alpha value.
alpha = imageData.alpha;
}
else if (imageData.alphaData != null) {
// If it has alpha data.
alpha = imageData.getAlpha(x, y);
}
alphaData[i++] = (byte) (alpha * HIGHLIGHT_ALPHA / 255);
}
}
return alphaData;
}
/**
* Create the alpha data for the base image that has mask data, and the color depth is not of
* 32-bit.
*
* @return The alpha data
*/
private byte[] maskAlpha() {
ImageData imageData = baseImage.getImageData();
Assert.isTrue(imageData.maskData != null && imageData.depth != 32);
ImageData mask = imageData.getTransparencyMask();
// Get the black index.
int blackIndex = getBlackIndex(mask);
byte[] alphaData = new byte[imageData.width * imageData.height];
int i = 0;
for (int y = 0; y < imageData.height; y++) {
for (int x = 0; x < imageData.width; x++) {
int alpha = mask.getPixel(x, y) == blackIndex ? 0 : 255;
alphaData[i++] = (byte) (alpha * HIGHLIGHT_ALPHA / 255);
}
}
return alphaData;
}
/**
* Create the alpha data for the base image that has mask data and the color depth is of 32-bit.
*
* @return The alpha data.
*/
private byte[] maskAlpha32() {
ImageData imageData = baseImage.getImageData();
Assert.isTrue(imageData.maskData != null && imageData.depth == 32);
ImageData mask = imageData.getTransparencyMask();
// Get the black index.
int blackIndex = getBlackIndex(mask);
// Calculate the alpha mask and the alpha shift.
int alphaMask = ~(imageData.palette.redMask | imageData.palette.greenMask | imageData.palette.blueMask);
int alphaShift = 0;
while (alphaMask != 0 && ((alphaMask >>> alphaShift) & 1) == 0)
alphaShift++;
byte[] alphaData = new byte[imageData.width * imageData.height];
int i = 0;
for (int y = 0; y < imageData.height; y++) {
for (int x = 0; x < imageData.width; x++) {
int pixel = imageData.getPixel(x, y);
int alpha = (pixel & alphaMask) >>> alphaShift;
if (alpha <= 0 || alpha > 255) {
// If the alpha value is illegal, try to get it from the mask data.
alpha = mask.getPixel(x, y) == blackIndex ? 0 : 255;
}
alphaData[i++] = (byte) (alpha * HIGHLIGHT_ALPHA / 255);
}
}
return alphaData;
}
/**
* Get the black index from the palette of the mask data.
*
* @param mask
* @return
*/
private int getBlackIndex(ImageData mask) {
RGB[] rgbs = mask.getRGBs();
if (rgbs != null) {
for (int i = 0; i < rgbs.length; i++) {
RGB rgb = rgbs[i];
if (rgb.red == 0 && rgb.green == 0 && rgb.blue == 0) {
return i;
}
}
}
return 0;
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.resource.CompositeImageDescriptor#getSize()
*/
@Override
protected Point getSize() {
return new Point(baseImage.getImageData().width, baseImage.getImageData().height);
}
/*
* (non-Javadoc)
* @see org.eclipse.tcf.te.tcf.ide.util.ui.AbstractImageDescriptor#getBaseImage()
*/
@Override
protected Image getBaseImage() {
return baseImage;
}
}