package org.simantics.utils.ui.color; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; public class ColorAlphaGradient extends ColorGradient { List alphaValues; public ColorAlphaGradient() { super(); this.alphaValues = new ArrayList<>(); } public ColorAlphaGradient(ColorAlphaGradient copyFrom) { super(copyFrom); this.alphaValues = copyFrom.alphaValues; } public ColorAlphaGradient(ColorValue array[], int alphaArray[]) { super(array); if (array.length != alphaArray.length) throw new IllegalArgumentException("Array lenghts do not match."); this.alphaValues = new ArrayList<>(alphaArray.length); for (int a : alphaArray) { alphaValues.add(a); } } public ColorAlphaGradient(ColorValue array[], int alphaArray[], int type) { super(array, type); if (array.length != alphaArray.length) throw new IllegalArgumentException("Array lenghts do not match."); this.alphaValues = new ArrayList<>(alphaArray.length); for (int a : alphaArray) { alphaValues.add(a); } } public ColorAlphaGradient(Collection values, Collection alphaValues) { super(values); if (values.size() != alphaValues.size()) throw new IllegalArgumentException("Array lenghts do not match."); this.alphaValues = new ArrayList<>(alphaValues); } public ColorAlphaGradient(Collection values, Collection alphaValues, int type) { super(values, type); if (values.size() != alphaValues.size()) throw new IllegalArgumentException("Array lenghts do not match."); this.alphaValues = new ArrayList<>(alphaValues); } /** * Interpolates color in RGB space * * @param value * @return */ private byte[] getRGBColor(double value) { int index = 1; while (values.get(index).getValue() <= value && index < values.size()-1) index++; value -= values.get(index - 1).getValue(); value /= (values.get(index).getValue() - values.get(index - 1).getValue()); double valuei = 1.0 - value; byte color[] = new byte[] { (byte) Math.min(255.0, Math.floor(value * values.get(index).getColor().getR() + valuei * values.get(index - 1).getColor().getR())), (byte) Math.min(255.0, Math.floor(value * values.get(index).getColor().getG() + valuei * values.get(index - 1).getColor().getG())), (byte) Math.min(255.0, Math.floor(value * values.get(index).getColor().getB() + valuei * values.get(index - 1).getColor().getB())), (byte) Math.min(255.0, Math.floor(value * alphaValues.get(index) + valuei * alphaValues.get(index - 1)))}; return color; } /** * Interpolates color in HSV space * * @param value * @return */ private byte[] getHSVColor(double value) { int index = 1; while (values.get(index).getValue() <= value && index < values.size()-1) index++; value -= values.get(index - 1).getValue(); value /= (values.get(index).getValue() - values.get(index - 1).getValue()); double valuei = 1.0 - value; double h; if (Float.isNaN(values.get(index).getColor().getH())) { h = values.get(index-1).getColor().getH(); } else if (Float.isNaN(values.get(index-1).getColor().getH())) { h = values.get(index).getColor().getH(); } else { // selecting shortest direction between hues float angle = values.get(index).getColor().getH() - values.get(index - 1).getColor().getH(); if (angle > 180.f) angle -= 360.f; else if (angle < -180.f) angle += 360.f; h = values.get(index - 1).getColor().getH() + value * angle; if (h > 360.f) h -= 360.f; else if (h < 0.f) h+= 360.f; } org.simantics.utils.ui.color.Color interpolated = new org.simantics.utils.ui.color.Color(h, value * values.get(index).getColor().getS() + valuei * values.get(index - 1).getColor().getS(), value * values.get(index).getColor().getV() + valuei * values.get(index - 1).getColor().getV()); byte color[] = new byte[] { (byte) interpolated.getR(), (byte) interpolated.getG(), (byte) interpolated.getB(), (byte) Math.min(255.0, Math.floor(value * alphaValues.get(index) + valuei * alphaValues.get(index - 1)))}; return color; } /** *

* Returns gradient in array of bytes. Array is RGB order and int contains 3 * requested size of bytes. *

*

* If gradient contains only one color array is filled with that color *

*

* if gradient has no colors array is filled with white *

* @param size number of pixels * @return gradient in array of bytes */ public byte[] getGradientArray(int size) { byte array[] = new byte[size * 4]; if (values.size() > 1) { for (int i = 0; i < size; i++) { int index = i * 4; double value = values.get(0).getValue() + (values.get(values.size() - 1).getValue() - values.get(0).getValue()) * (double) i / (double) size; byte color[]; if (type == RGB) color = getRGBColor(value); else color = getHSVColor(value); array[index] = color[0]; array[index + 1] = color[1]; array[index + 2] = color[2]; array[index + 3] = color[3]; } } else if (values.size() == 1) { byte color[] = new byte[3]; color[0] = (byte)values.get(0).getColor().getR(); color[1] = (byte)values.get(0).getColor().getG(); color[2] = (byte)values.get(0).getColor().getB(); color[3] = (byte)(int)alphaValues.get(0); for (int i = 0; i < size; i++) { int index = i * 3; array[index] = color[0]; array[index + 1] = color[1]; array[index + 2] = color[2]; array[index + 3] = color[3]; } } else { for (int i = 0; i < size; i++) { int index = i * 4; array[index] = (byte)255; array[index + 1] = (byte)255; array[index + 2] = (byte)255; array[index + 3] = (byte)255; } } return array; } /** *

* Returns gradient in image. *

*

* If gradient contains only one color image is filled with that color *

*

* if gradient has no colors image is filled with white *

*

* Style must be set to SWT.HORIZONTAL or SWT.VERTICAL *

* @param size number of pixels * @return gradient in array of bytes */ public Image getGradientImage(int width, int height, int style) { Image image = new Image(Display.getCurrent(), width, height); GC gc = new GC(image); gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); gc.fillRectangle(0, 0, width, height); if (values.size() > 1) { if (SWT.HORIZONTAL == (style | SWT.HORIZONTAL)) { for (int x = 0; x < width; x++) { double value = values.get(0).getValue() + (values.get(values.size() - 1).getValue() - values.get(0).getValue()) * (double) x / (double) (width - 1); byte byteColor[]; if (type == RGB) byteColor = getRGBColor(value); else byteColor = getHSVColor(value); Color color = new Color(Display.getCurrent(), byteColor[0] & 0xff, byteColor[1] & 0xff, byteColor[2] & 0xff, byteColor[3] & 0xff); gc.setForeground(color); gc.drawLine(x, 0, x, height); color.dispose(); } } else if (SWT.VERTICAL == (style | SWT.VERTICAL)){ for (int y = 0; y < height; y++) { double value = values.get(0).getValue() + (values.get(values.size() - 1).getValue() - values.get(0).getValue()) * (double) y / (double) (height - 1); byte byteColor[]; if (type == RGB) byteColor = getRGBColor(value); else byteColor = getHSVColor(value); Color color = new Color(Display.getCurrent(), byteColor[0] & 0xff, byteColor[1] & 0xff, byteColor[2] & 0xff, byteColor[3] & 0xff); gc.setForeground(color); gc.drawLine(0, y, width, y); color.dispose(); } } else { gc.dispose(); image.dispose(); SWT.error(SWT.ERROR_INVALID_ARGUMENT); } } else if (values.size() == 1) { Color color = new Color(Display.getCurrent(), values.get(0).getColor().getR(), values.get(0).getColor().getG(), values.get(0).getColor().getB(), alphaValues.get(0)); gc.setBackground(color); gc.fillRectangle(0, 0, width, height); color.dispose(); } else { gc.fillRectangle(0, 0, width, height); } gc.dispose(); return image; } @Override public boolean equals(Object obj) { if (super.equals(obj)) { ColorAlphaGradient cg = (ColorAlphaGradient)obj; return alphaValues.containsAll(cg.alphaValues); } else { return false; } } }