blob: 88619a4960a68fe62743b72cbdfebf2fce148814 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2008 Tasktop Technologies 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:
* Tasktop Technologies - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.internal.context.ui;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Display;
/**
* @author Mik Kersten
*/
public class HighlighterImageDescriptor extends ImageDescriptor {
private final Image image;
public HighlighterImageDescriptor(Color fromColor, Color toColor) {
super();
if (fromColor == null) {
fromColor = Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
}
if (toColor == null) {
toColor = Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
}
ImageData band = createGradientBand(50, 20, false, new RGB(fromColor.getRed(), fromColor.getGreen(),
fromColor.getBlue()), new RGB(toColor.getRed(), toColor.getGreen(), toColor.getBlue()), 7, 7, 7);
image = new Image(Display.getCurrent(), band);
}
@Override
public void destroyResource(Object previouslyCreatedObject) {
image.dispose();
super.destroyResource(previouslyCreatedObject);
}
@Override
public boolean equals(Object obj) {
return obj instanceof HighlighterImageDescriptor && image.equals(((HighlighterImageDescriptor) obj).image);
}
@Override
public ImageData getImageData() {
return image.getImageData();
}
@Override
public int hashCode() {
return image.hashCode();
}
public Image getImage() {
return image;
}
// ----------- COPIED FROM ImageData ---------------
/**
* Creates an ImageData containing one band's worth of a gradient filled block. If <code>vertical</code> is true,
* the band must be tiled horizontally to fill a region, otherwise it must be tiled vertically.
*
* @param width
* the width of the region to be filled
* @param height
* the height of the region to be filled
* @param vertical
* if true sweeps from top to bottom, else sweeps from left to right
* @param fromRGB
* the color to start with
* @param toRGB
* the color to end with
* @param redBits
* the number of significant red bits, 0 for palette modes
* @param greenBits
* the number of significant green bits, 0 for palette modes
* @param blueBits
* the number of significant blue bits, 0 for palette modes
* @return the new ImageData
*/
static ImageData createGradientBand(int width, int height, boolean vertical, RGB fromRGB, RGB toRGB, int redBits,
int greenBits, int blueBits) {
/* Gradients are drawn as tiled bands */
final int bandWidth, bandHeight, bitmapDepth;
final byte[] bitmapData;
final PaletteData paletteData;
/* Select an algorithm depending on the depth of the screen */
if (redBits != 0 && greenBits != 0 && blueBits != 0) {
paletteData = new PaletteData(0x0000ff00, 0x00ff0000, 0xff000000);
bitmapDepth = 32;
if (redBits >= 8 && greenBits >= 8 && blueBits >= 8) {
/* Precise color */
final int steps;
if (vertical) {
bandWidth = 1;
bandHeight = height;
steps = bandHeight > 1 ? bandHeight - 1 : 1;
} else {
bandWidth = width;
bandHeight = 1;
steps = bandWidth > 1 ? bandWidth - 1 : 1;
}
final int bytesPerLine = bandWidth * 4;
bitmapData = new byte[bandHeight * bytesPerLine];
buildPreciseGradientChannel(fromRGB.blue, toRGB.blue, steps, bandWidth, bandHeight, vertical,
bitmapData, 0, bytesPerLine);
buildPreciseGradientChannel(fromRGB.green, toRGB.green, steps, bandWidth, bandHeight, vertical,
bitmapData, 1, bytesPerLine);
buildPreciseGradientChannel(fromRGB.red, toRGB.red, steps, bandWidth, bandHeight, vertical, bitmapData,
2, bytesPerLine);
} else {
/* Dithered color */
final int steps;
if (vertical) {
bandWidth = (width < 8) ? width : 8;
bandHeight = height;
steps = bandHeight > 1 ? bandHeight - 1 : 1;
} else {
bandWidth = width;
bandHeight = (height < 8) ? height : 8;
steps = bandWidth > 1 ? bandWidth - 1 : 1;
}
final int bytesPerLine = bandWidth * 4;
bitmapData = new byte[bandHeight * bytesPerLine];
buildDitheredGradientChannel(fromRGB.blue, toRGB.blue, steps, bandWidth, bandHeight, vertical,
bitmapData, 0, bytesPerLine, blueBits);
buildDitheredGradientChannel(fromRGB.green, toRGB.green, steps, bandWidth, bandHeight, vertical,
bitmapData, 1, bytesPerLine, greenBits);
buildDitheredGradientChannel(fromRGB.red, toRGB.red, steps, bandWidth, bandHeight, vertical,
bitmapData, 2, bytesPerLine, redBits);
}
} else {
/* Dithered two tone */
paletteData = new PaletteData(new RGB[] { fromRGB, toRGB });
bitmapDepth = 8;
final int blendi;
if (vertical) {
bandWidth = (width < 8) ? width : 8;
bandHeight = height;
blendi = (bandHeight > 1) ? 0x1040000 / (bandHeight - 1) + 1 : 1;
} else {
bandWidth = width;
bandHeight = (height < 8) ? height : 8;
blendi = (bandWidth > 1) ? 0x1040000 / (bandWidth - 1) + 1 : 1;
}
final int bytesPerLine = (bandWidth + 3) & -4;
bitmapData = new byte[bandHeight * bytesPerLine];
if (vertical) {
for (int dy = 0, blend = 0, dp = 0; dy < bandHeight; ++dy, blend += blendi, dp += bytesPerLine) {
for (int dx = 0; dx < bandWidth; ++dx) {
bitmapData[dp + dx] = (blend + DITHER_MATRIX[dy & 7][dx]) < 0x1000000 ? (byte) 0 : (byte) 1;
}
}
} else {
for (int dx = 0, blend = 0; dx < bandWidth; ++dx, blend += blendi) {
for (int dy = 0, dptr = dx; dy < bandHeight; ++dy, dptr += bytesPerLine) {
bitmapData[dptr] = (blend + DITHER_MATRIX[dy][dx & 7]) < 0x1000000 ? (byte) 0 : (byte) 1;
}
}
}
}
return new ImageData(bandWidth, bandHeight, bitmapDepth, paletteData, 4, bitmapData);
}
/*
* Fill in dithered gradated values for a color channel
*/
static final void buildDitheredGradientChannel(int from, int to, int steps, int bandWidth, int bandHeight,
boolean vertical, byte[] bitmapData, int dp, int bytesPerLine, int bits) {
final int mask = 0xff00 >>> bits;
int val = from << 16;
final int inc = ((to << 16) - val) / steps + 1;
if (vertical) {
for (int dy = 0; dy < bandHeight; ++dy, dp += bytesPerLine) {
for (int dx = 0, dptr = dp; dx < bandWidth; ++dx, dptr += 4) {
final int thresh = DITHER_MATRIX[dy & 7][dx] >>> bits;
int temp = val + thresh;
if (temp > 0xffffff) {
bitmapData[dptr] = -1;
} else {
bitmapData[dptr] = (byte) ((temp >>> 16) & mask);
}
}
val += inc;
}
} else {
for (int dx = 0; dx < bandWidth; ++dx, dp += 4) {
for (int dy = 0, dptr = dp; dy < bandHeight; ++dy, dptr += bytesPerLine) {
final int thresh = DITHER_MATRIX[dy][dx & 7] >>> bits;
int temp = val + thresh;
if (temp > 0xffffff) {
bitmapData[dptr] = -1;
} else {
bitmapData[dptr] = (byte) ((temp >>> 16) & mask);
}
}
val += inc;
}
}
}
/*
* Fill in gradated values for a color channel
*/
static final void buildPreciseGradientChannel(int from, int to, int steps, int bandWidth, int bandHeight,
boolean vertical, byte[] bitmapData, int dp, int bytesPerLine) {
int val = from << 16;
final int inc = ((to << 16) - val) / steps + 1;
if (vertical) {
for (int dy = 0; dy < bandHeight; ++dy, dp += bytesPerLine) {
bitmapData[dp] = (byte) (val >>> 16);
val += inc;
}
} else {
for (int dx = 0; dx < bandWidth; ++dx, dp += 4) {
bitmapData[dp] = (byte) (val >>> 16);
val += inc;
}
}
}
/**
* Scaled 8x8 Bayer dither matrix.
*/
static final int[][] DITHER_MATRIX = {
{ 0xfc0000, 0x7c0000, 0xdc0000, 0x5c0000, 0xf40000, 0x740000, 0xd40000, 0x540000 },
{ 0x3c0000, 0xbc0000, 0x1c0000, 0x9c0000, 0x340000, 0xb40000, 0x140000, 0x940000 },
{ 0xcc0000, 0x4c0000, 0xec0000, 0x6c0000, 0xc40000, 0x440000, 0xe40000, 0x640000 },
{ 0x0c0000, 0x8c0000, 0x2c0000, 0xac0000, 0x040000, 0x840000, 0x240000, 0xa40000 },
{ 0xf00000, 0x700000, 0xd00000, 0x500000, 0xf80000, 0x780000, 0xd80000, 0x580000 },
{ 0x300000, 0xb00000, 0x100000, 0x900000, 0x380000, 0xb80000, 0x180000, 0x980000 },
{ 0xc00000, 0x400000, 0xe00000, 0x600000, 0xc80000, 0x480000, 0xe80000, 0x680000 },
{ 0x000000, 0x800000, 0x200000, 0xa00000, 0x080000, 0x880000, 0x280000, 0xa80000 } };
}