blob: d01b67c67e0f72ad29a755c7da2f987d38ecc99c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2017 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Wang Yizhuo (wangyizhuo@gmail.com) - patch (see Bugzilla #239178)
* Simon Scholz <simon.scholz@vogella.com> - Bug 430205, 458055
* Ralf M Petter <ralf.petter@gmail.com> - Bug 510826
*******************************************************************************/
package org.eclipse.ui.internal.forms.widgets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Display;
public class FormImages {
private static FormImages instance;
public static FormImages getInstance() {
if (instance == null)
instance = new FormImages();
return instance;
}
private ResourceManagerManger manager = new ResourceManagerManger();
private Map<Integer, AbstractImageDescriptor> descriptors;
private FormImages() {
}
private abstract static class AbstractImageDescriptor extends ImageDescriptor {
RGB[] fRGBs;
int fLength;
AbstractImageDescriptor(Color[] colors, int length) {
fRGBs = new RGB[colors.length];
for (int i = 0; i < colors.length; i++) {
Color color = colors[i];
fRGBs[i] = color == null ? null : color.getRGB();
}
fLength = length;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof AbstractImageDescriptor) {
AbstractImageDescriptor id = (AbstractImageDescriptor)obj;
return fLength == id.fLength && Arrays.equals(fRGBs, id.fRGBs);
}
return false;
}
@Override
public int hashCode() {
int hash = 0;
for (RGB fRGB : fRGBs)
hash = hash * 7 + fRGB.hashCode();
return hash * 7 + fLength;
}
}
private class SimpleImageDescriptor extends AbstractImageDescriptor{
private int fTheight;
private int fMarginHeight;
SimpleImageDescriptor (Color color1, Color color2,
int realtheight, int theight, int marginHeight) {
super(new Color[] {color1, color2}, realtheight);
fTheight = theight;
fMarginHeight = marginHeight;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof SimpleImageDescriptor) {
SimpleImageDescriptor id = (SimpleImageDescriptor) obj;
if (super.equals(obj) &&
id.fTheight == fTheight && id.fMarginHeight == fMarginHeight)
return true;
}
return false;
}
@Override
public int hashCode() {
int hash = super.hashCode();
hash = hash * 7 + Integer.valueOf(fTheight).hashCode();
return hash * 7 + Integer.valueOf(fMarginHeight).hashCode();
}
@Override
public ImageData getImageData() {
return null;
}
@Override
public Image createImage(boolean returnMissingImageOnError, Device device) {
Image image = new Image(device, 1, fLength);
Color color1 = new Color(device, fRGBs[0]);
Color color2 = new Color(device, fRGBs[1]);
image.setBackground(color1);
GC gc = new GC(image);
gc.setBackground(color1);
gc.fillRectangle(0, 0, 1, fLength);
gc.setForeground(color2);
gc.setBackground(color1);
gc.fillGradientRectangle(0, fMarginHeight + 2, 1, fTheight - 2, true);
gc.dispose();
return image;
}
}
private class ComplexImageDescriptor extends AbstractImageDescriptor {
RGB fBgRGB;
boolean fVertical;
int[] fPercents;
public ComplexImageDescriptor(Color[] colors, int length,
int[] percents, boolean vertical, Color bg) {
super(colors, length);
fBgRGB = bg == null ? null : bg.getRGB();
fVertical = vertical;
fPercents = percents;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ComplexImageDescriptor) {
ComplexImageDescriptor id = (ComplexImageDescriptor) obj;
if (super.equals(obj) &&
id.fVertical == fVertical && Arrays.equals(id.fPercents, fPercents)) {
if (Objects.equals(fBgRGB, id.fBgRGB)) {
return true;
}
// if the only thing that isn't the same is the background color
// still return true if it does not matter (percents add up to 100)
int sum = 0;
for (int fPercent : fPercents)
sum += fPercent;
if (sum >= 100)
return true;
}
}
return false;
}
@Override
public int hashCode() {
int hash = super.hashCode();
hash = hash * 7 + Boolean.hashCode(fVertical);
for (int fPercent : fPercents) {
hash = hash * 7 + Integer.hashCode(fPercent);
}
return hash;
}
@Override
public ImageData getImageData() {
return null;
}
@Override
public Image createImage(boolean returnMissingImageOnError, Device device) {
int width = fVertical ? 1 : fLength;
int height = fVertical ? fLength : 1;
Image gradient = new Image(device, Math.max(width, 1), Math
.max(height, 1));
GC gc = new GC(gradient);
Color[] colors = new Color[fRGBs.length];
for (int i = 0; i < colors.length; i++)
colors[i] = new Color(device, fRGBs[i]);
Color bg = fBgRGB == null ? null : new Color(device, fBgRGB);
drawTextGradient(gc, width, height, colors, fPercents, fVertical, bg);
gc.dispose();
return gradient;
}
private void drawTextGradient(GC gc, int width, int height, Color[] colors,
int[] percents, boolean vertical, Color bg) {
final Color oldBackground = gc.getBackground();
if (colors.length == 1) {
if (colors[0] != null)
gc.setBackground(colors[0]);
gc.fillRectangle(0, 0, width, height);
} else {
final Color oldForeground = gc.getForeground();
Color lastColor = colors[0];
if (lastColor == null)
lastColor = oldBackground;
int pos = 0;
for (int i = 0; i < percents.length; ++i) {
gc.setForeground(lastColor);
lastColor = colors[i + 1];
if (lastColor == null)
lastColor = oldBackground;
gc.setBackground(lastColor);
if (vertical) {
int gradientHeight = percents[i] * height / 100;
gc.fillGradientRectangle(0, pos, width, gradientHeight,
true);
pos += gradientHeight;
} else {
int gradientWidth = percents[i] * width / 100;
gc.fillGradientRectangle(pos, 0, gradientWidth, height,
false);
pos += gradientWidth;
}
}
if (vertical && pos < height) {
if (bg != null)
gc.setBackground(bg);
gc.fillRectangle(0, pos, width, height - pos);
}
if (!vertical && pos < width) {
if (bg != null)
gc.setBackground(bg);
gc.fillRectangle(pos, 0, width - pos, height);
}
gc.setForeground(oldForeground);
}
}
}
private class SimpleSectionImageDescriptor extends AbstractImageDescriptor {
protected int fTheight;
protected int fMarginHeight;
SimpleSectionImageDescriptor(Color[] colors, int realtheight, int theight, int marginHeight) {
super(colors, realtheight);
fTheight = theight;
fMarginHeight = marginHeight;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof SimpleSectionImageDescriptor) {
SimpleSectionImageDescriptor id = (SimpleSectionImageDescriptor) obj;
if (super.equals(obj) && id.fTheight == fTheight && id.fMarginHeight == fMarginHeight)
return true;
}
return false;
}
@Override
public int hashCode() {
int hash = super.hashCode();
hash = hash * 7 + Integer.hashCode(fTheight);
return hash * 7 + Integer.hashCode(fMarginHeight);
}
@Override
public ImageData getImageData() {
return null;
}
@Override
public Image createImage(boolean returnMissingImageOnError, Device device) {
Image image = new Image(device, 1, fLength);
Color originalBgColor = new Color(device, fRGBs[0]);
Color color1 = new Color(device, fRGBs[1]);
image.setBackground(originalBgColor);
GC gc = new GC(image);
gc.setBackground(color1);
gc.fillRectangle(0, fMarginHeight + 2, 1, fTheight - fMarginHeight - 3);
gc.setBackground(originalBgColor);
gc.fillRectangle(0, fTheight - fMarginHeight - 4, 1, 4);
gc.dispose();
return image;
}
}
private class SimpleSectionGradientImageDescriptor extends SimpleSectionImageDescriptor {
SimpleSectionGradientImageDescriptor(Color color1, Color color2, int realtheight,
int theight,
int marginHeight) {
super(new Color[] { color1, color2 }, realtheight, theight, marginHeight);
}
@Override
public Image createImage(boolean returnMissingImageOnError, Device device) {
Image image = new Image(device, 1, fLength);
Color color1 = new Color(device, fRGBs[0]);
Color color2 = new Color(device, fRGBs[1]);
image.setBackground(color1);
GC gc = new GC(image);
gc.setBackground(color1);
gc.fillRectangle(0, 0, 1, fLength);
gc.setForeground(color2);
gc.setBackground(color1);
gc.fillGradientRectangle(0, fMarginHeight + 2, 1, fTheight - 2, true);
gc.dispose();
return image;
}
}
public Image getSectionGradientImage(Color color1, Color color2, int realtheight, int theight, int marginHeight,
Display display) {
if (color1 == null || color1.isDisposed())
return null;
AbstractImageDescriptor desc = new SimpleSectionGradientImageDescriptor(color1, color2,
realtheight, theight, marginHeight);
return getGradient(desc, display);
}
public Image getGradient(Color color1, Color color2,
int realtheight, int theight, int marginHeight, Display display) {
if (color1 == null || color1.isDisposed() || color2 == null || color2.isDisposed())
return null;
AbstractImageDescriptor desc = new SimpleImageDescriptor(color1, color2, realtheight, theight, marginHeight);
return getGradient(desc, display);
}
public Image getGradient(Color[] colors, int[] percents,
int length, boolean vertical, Color bg, Display display) {
if (colors.length == 0)
return null;
for (Color color : colors)
if (color == null || color.isDisposed())
return null;
if (bg != null && bg.isDisposed())
return null;
AbstractImageDescriptor desc = new ComplexImageDescriptor(colors, length, percents, vertical, bg);
return getGradient(desc, display);
}
private synchronized Image getGradient(AbstractImageDescriptor desc, Display display) {
checkHashMaps();
Image result = manager.getResourceManager(display).createImage(desc);
descriptors.put(Integer.valueOf(result.hashCode()), desc);
return result;
}
public synchronized boolean markFinished(Image image, Display display) {
checkHashMaps();
Integer imageHashCode = Integer.valueOf(image.hashCode());
AbstractImageDescriptor desc = descriptors.get(imageHashCode);
if (desc != null) {
LocalResourceManager resourceManager = manager.getResourceManager(display);
resourceManager.destroyImage(desc);
if (resourceManager.find(desc) == null) {
descriptors.remove(imageHashCode);
validateHashMaps();
}
return true;
}
// if the image was not found, dispose of it for the caller
image.dispose();
validateHashMaps();
return false;
}
private void checkHashMaps() {
if (descriptors == null)
descriptors = new HashMap<>();
}
private void validateHashMaps() {
if (descriptors.isEmpty())
descriptors = null;
}
}