]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/color/ColorGradient.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.utils.ui / src / org / simantics / utils / ui / color / ColorGradient.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.utils.ui.color;
13
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.List;
18
19 import org.eclipse.swt.SWT;
20 import org.eclipse.swt.graphics.Color;
21 import org.eclipse.swt.graphics.GC;
22 import org.eclipse.swt.graphics.Image;
23 import org.eclipse.swt.widgets.Display;
24
25 /**
26  * 
27  * <p>
28  * Color gradient between multiple colors
29  * </p>
30  * <p>
31  * Supports RGB and HSV linear interpolation between colors
32  * </p>
33  * 
34  * @author Marko Luukkainen
35  *
36  */
37 public class ColorGradient {
38     public static final int RGB = 0;
39
40     public static final int HSV = 1;
41
42     protected ArrayList<ColorValue> values;
43
44     protected int type;
45     
46     public ColorGradient() {
47         this.values = new ArrayList<ColorValue>();
48         this.type = RGB;
49     }
50
51     public ColorGradient(ColorGradient copyFrom) {
52         this.values = new ArrayList<ColorValue>(copyFrom.values);
53         this.type = copyFrom.type;
54     }
55
56     public ColorGradient(Collection<ColorValue> values) {
57         this.values = new ArrayList<ColorValue>(values);
58         Collections.sort(this.values, new ColorValueComparator());
59         this.type = RGB;
60     }
61
62     public ColorGradient(ColorValue array[]) {
63         this.values = new ArrayList<ColorValue>(array.length);
64         for (ColorValue c : array) {
65             values.add(c);
66         }
67         Collections.sort(this.values, new ColorValueComparator());
68         this.type = RGB;
69     }
70
71     public ColorGradient(Collection<ColorValue> values, int type) {
72         this.values = new ArrayList<ColorValue>(values);
73         Collections.sort(this.values, new ColorValueComparator());
74         this.type = type;
75     }
76
77     public ColorGradient(ColorValue array[], int type) {
78         this.values = new ArrayList<ColorValue>();
79         for (ColorValue c : array) {
80             values.add(c);
81         }
82         Collections.sort(this.values, new ColorValueComparator());
83         this.type = type;
84     }
85
86     /**
87      * Interpolates color in RGB space
88      * 
89      * @param value
90      * @return
91      */
92     private byte[] getRGBColor(double value) {
93         int index = 1;
94         while (values.get(index).getValue() <= value && index < values.size()-1)
95             index++;
96
97         value -= values.get(index - 1).getValue();
98         value /= (values.get(index).getValue() - values.get(index - 1).getValue());
99         double valuei = 1.0 - value;
100         byte color[] = new byte[] {
101                 (byte) Math.min(255.0, Math.floor(value * values.get(index).getColor().getR() + valuei * values.get(index - 1).getColor().getR())),
102                 (byte) Math.min(255.0, Math.floor(value * values.get(index).getColor().getG() + valuei * values.get(index - 1).getColor().getG())),
103                 (byte) Math.min(255.0, Math.floor(value * values.get(index).getColor().getB() + valuei * values.get(index - 1).getColor().getB())) };
104         return color;
105
106     }
107
108     /**
109      * Interpolates color in HSV space
110      * 
111      * @param value
112      * @return
113      */
114     private byte[] getHSVColor(double value) {
115         int index = 1;
116         while (values.get(index).getValue() <= value && index < values.size()-1)
117             index++;
118
119         value -= values.get(index - 1).getValue();
120         value /= (values.get(index).getValue() - values.get(index - 1).getValue());
121         double valuei = 1.0 - value;
122         double h;
123         if (Float.isNaN(values.get(index).getColor().getH())) {
124             h = values.get(index-1).getColor().getH();
125         } else if (Float.isNaN(values.get(index-1).getColor().getH())) {
126             h = values.get(index).getColor().getH();
127         } else {
128             // selecting shortest direction between hues
129             float angle = values.get(index).getColor().getH() - values.get(index - 1).getColor().getH();
130             if (angle > 180.f)
131                 angle -= 360.f;
132             else if (angle < -180.f)
133                 angle += 360.f;
134             h = values.get(index - 1).getColor().getH() + value * angle;
135             if (h > 360.f)
136                 h -= 360.f;
137             else if (h < 0.f)
138                 h+= 360.f;
139         }
140         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(),
141                 value * values.get(index).getColor().getV() + valuei * values.get(index - 1).getColor().getV());
142         byte color[] = new byte[] { (byte) interpolated.getR(), (byte) interpolated.getG(), (byte) interpolated.getB() };
143
144         return color;
145
146     }
147
148     /**
149      * <p>
150      * Returns gradient in array of bytes. Array is RGB order and int contains 3 * requested size of bytes.
151      * </p>
152      * <p>
153      * If gradient contains only one color array is filled with that color
154      * </p>
155      * <p>
156      * if gradient has no colors array is filled with white
157      * </p>
158      * @param size number of pixels
159      * @return gradient in array of bytes
160      */
161     public byte[] getGradientArray(int size) {
162         byte array[] = new byte[size * 3];
163         if (values.size() > 1) {
164             for (int i = 0; i < size; i++) {
165                 int index = i * 3;
166                 double value = values.get(0).getValue() + (values.get(values.size() - 1).getValue() - values.get(0).getValue()) * (double) i / (double) size;
167                 byte color[];
168                 if (type == RGB)
169                     color = getRGBColor(value);
170                 else
171                     color = getHSVColor(value);
172                 array[index] = color[0];
173                 array[index + 1] = color[1];
174                 array[index + 2] = color[2];
175             }
176         } else if (values.size() == 1) {
177             byte color[] = new byte[3];
178             color[0] = (byte)values.get(0).getColor().getR();
179             color[1] = (byte)values.get(0).getColor().getG();
180             color[2] = (byte)values.get(0).getColor().getB();
181             for (int i = 0; i < size; i++) {
182                 int index = i * 3;
183                 array[index] = color[0];
184                 array[index + 1] = color[1];
185                 array[index + 2] = color[2];
186             }
187         } else {
188             for (int i = 0; i < size; i++) {
189                 int index = i * 3;
190                 array[index] = (byte)255;
191                 array[index + 1] = (byte)255;
192                 array[index + 2] = (byte)255;
193             }
194         }
195         return array;
196     }
197
198     /**
199      * <p>
200      * Returns gradient in image.
201      * </p>
202      * <p>
203      * If gradient contains only one color image is filled with that color
204      * </p>
205      * <p>
206      * if gradient has no colors image is filled with white
207      * </p>
208      * <p>
209      * Style must be set to  <code>SWT.HORIZONTAL</code> or <code>SWT.VERTICAL</code>
210      * </p>
211      * @param size number of pixels
212      * @return gradient in array of bytes
213      */
214     
215     public Image getGradientImage(int width, int height, int style) {
216         Image image = new Image(Display.getCurrent(), width, height);
217         GC gc = new GC(image);
218         gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
219         gc.fillRectangle(0, 0, width, height);
220         if (values.size() > 1) {
221             if (SWT.HORIZONTAL == (style | SWT.HORIZONTAL)) {
222                 for (int x = 0; x < width; x++) {
223                     double value = values.get(0).getValue() + (values.get(values.size() - 1).getValue() - values.get(0).getValue()) * (double) x
224                             / (double) (width - 1);
225                     byte byteColor[];
226                     if (type == RGB)
227                         byteColor = getRGBColor(value);
228                     else
229                         byteColor = getHSVColor(value);
230                     Color color = new Color(Display.getCurrent(), byteColor[0] & 0xff, byteColor[1] & 0xff, byteColor[2] & 0xff);
231                     gc.setForeground(color);
232                     gc.drawLine(x, 0, x, height);
233                     color.dispose();
234                 }
235             } else if (SWT.VERTICAL == (style | SWT.VERTICAL)){
236                 for (int y = 0; y < height; y++) {
237                     double value = values.get(0).getValue() + (values.get(values.size() - 1).getValue() - values.get(0).getValue()) * (double) y
238                             / (double) (height - 1);
239                     byte byteColor[];
240                     if (type == RGB)
241                         byteColor = getRGBColor(value);
242                     else
243                         byteColor = getHSVColor(value);
244                     Color color = new Color(Display.getCurrent(), byteColor[0] & 0xff, byteColor[1] & 0xff, byteColor[2] & 0xff);
245                     gc.setForeground(color);
246                     gc.drawLine(0, y, width, y);
247                     color.dispose();
248                 }
249             } else {
250                 gc.dispose();
251                 image.dispose();
252                 SWT.error(SWT.ERROR_INVALID_ARGUMENT);
253             }
254         } else if (values.size() == 1) {
255             Color color = new Color(Display.getCurrent(), values.get(0).getColor().getR(), values.get(0).getColor().getG(), values.get(0).getColor().getB());      
256             gc.setBackground(color);
257             gc.fillRectangle(0, 0, width, height);
258             color.dispose();
259         } else {
260             gc.fillRectangle(0, 0, width, height);
261         }
262         gc.dispose();
263         return image;
264     }
265     
266     public int getType() {
267         return type;
268     }
269     
270     public List<ColorValue> getColorValues() {
271         return values;
272     }
273     
274     public ColorValue[] getColorValueArray() {
275         return values.toArray(new ColorValue[values.size()]);
276     }
277     
278     @Deprecated
279     public void addCastorColorValue(ColorValue value) {
280         values.add(value);
281         Collections.sort(this.values, new ColorValueComparator());
282     }
283     
284     @Deprecated
285     public void setCastorType(int type) {
286         this.type = type;
287     }
288     
289     @Override
290     public int hashCode() {
291         int hash = 0x58fb3;
292         for (ColorValue cv : values)
293             hash ^= cv.hashCode();
294         return hash;
295     }
296     
297     @Override
298     public boolean equals(Object obj) {
299         if (obj == null)
300                 return false;
301         if (obj.getClass() != getClass())
302                 return false;
303         ColorGradient cg = (ColorGradient) obj;
304         if (cg.type != type) return false;
305         if (values.size()!=cg.values.size()) return false;
306         if (!values.containsAll(cg.values)) return false;
307         return true;
308     }
309
310 }