]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/color/ColorGradientComposite.java
Sync git svn branch with SVN repository r33219.
[simantics/platform.git] / bundles / org.simantics.utils.ui / src / org / simantics / utils / ui / color / ColorGradientComposite.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.utils.ui.color;\r
13 \r
14 \r
15 import java.util.ArrayList;\r
16 import java.util.Collections;\r
17 import java.util.HashMap;\r
18 \r
19 import org.eclipse.jface.layout.GridDataFactory;\r
20 import org.eclipse.jface.util.IPropertyChangeListener;\r
21 import org.eclipse.jface.util.PropertyChangeEvent;\r
22 import org.eclipse.jface.viewers.CellEditor;\r
23 import org.eclipse.jface.viewers.ColorCellEditor;\r
24 import org.eclipse.jface.viewers.ICellEditorListener;\r
25 import org.eclipse.jface.viewers.ICellModifier;\r
26 import org.eclipse.jface.viewers.ILabelProviderListener;\r
27 import org.eclipse.jface.viewers.ISelectionChangedListener;\r
28 import org.eclipse.jface.viewers.IStructuredContentProvider;\r
29 import org.eclipse.jface.viewers.IStructuredSelection;\r
30 import org.eclipse.jface.viewers.ITableLabelProvider;\r
31 import org.eclipse.jface.viewers.SelectionChangedEvent;\r
32 import org.eclipse.jface.viewers.StructuredSelection;\r
33 import org.eclipse.jface.viewers.TableViewer;\r
34 import org.eclipse.jface.viewers.TextCellEditor;\r
35 import org.eclipse.jface.viewers.Viewer;\r
36 import org.eclipse.swt.SWT;\r
37 import org.eclipse.swt.events.SelectionEvent;\r
38 import org.eclipse.swt.events.SelectionListener;\r
39 import org.eclipse.swt.graphics.Image;\r
40 import org.eclipse.swt.graphics.RGB;\r
41 import org.eclipse.swt.layout.FillLayout;\r
42 import org.eclipse.swt.layout.GridLayout;\r
43 import org.eclipse.swt.widgets.Button;\r
44 import org.eclipse.swt.widgets.ColorDialog;\r
45 import org.eclipse.swt.widgets.Composite;\r
46 import org.eclipse.swt.widgets.Group;\r
47 import org.eclipse.swt.widgets.Table;\r
48 import org.eclipse.swt.widgets.TableColumn;\r
49 import org.eclipse.swt.widgets.TableItem;\r
50 \r
51 /**\r
52  * Widget to create and edit color gradients\r
53  * \r
54  * @author Marko Luukkainen\r
55  *\r
56  */\r
57 public class ColorGradientComposite extends Composite implements ISelectionChangedListener, ICellEditorListener, IPropertyChangeListener{\r
58         private static int ICON_WIDTH = 36;\r
59         private static int ICON_HEIGHT = 14;\r
60         \r
61         private static final String COLOR_ID = "Color";\r
62         private static final String VALUE_ID = "Value";\r
63         \r
64         \r
65         private ColorGradientCanvas gradientComposite;\r
66         private TableViewer viewer;\r
67         private Button addButton;\r
68         private Button editButton;\r
69         private Button removeButton;\r
70         private Button rgbButton;\r
71         private Button hsvButton;\r
72         private int type = ColorGradient.RGB;\r
73         \r
74         private ArrayList<ColorValue> values = new ArrayList<ColorValue>();\r
75         private HashMap<ColorValue,Image> images = new HashMap<ColorValue,Image>();\r
76         \r
77         public ColorGradientComposite(Composite parent, int style) {\r
78                 super(parent,style);\r
79                 GridLayout layout = new GridLayout(2,false);\r
80             this.setLayout(layout);\r
81             gradientComposite = new ColorGradientCanvas(this,SWT.HORIZONTAL);\r
82             \r
83            \r
84             \r
85 //          Group typeComposite = new Group(this,SWT.NONE);\r
86 //          typeComposite.setText("Interpolation");\r
87             Composite typeComposite = new Composite(this, SWT.NONE);\r
88             \r
89             typeComposite.setLayout(new GridLayout(1,false));\r
90             rgbButton = new Button(typeComposite,SWT.RADIO);\r
91             rgbButton.setSelection(true);\r
92             rgbButton.addSelectionListener(new SelectionListener() {\r
93                 public void widgetDefaultSelected(SelectionEvent e) {\r
94                         widgetSelected(e);\r
95                 }\r
96                 public void widgetSelected(SelectionEvent e) {\r
97                         rgbButton.setSelection(true);\r
98                         hsvButton.setSelection(false);\r
99                         type = ColorGradient.RGB;\r
100                         gradientComposite.setGradient(new ColorGradient(values,type));\r
101                 }\r
102             });\r
103             rgbButton.setText("RGB");\r
104             hsvButton = new Button(typeComposite,SWT.RADIO);\r
105             hsvButton.addSelectionListener(new SelectionListener() {\r
106                 public void widgetDefaultSelected(SelectionEvent e) {\r
107                         widgetSelected(e);\r
108                 }\r
109                 public void widgetSelected(SelectionEvent e) {\r
110                         hsvButton.setSelection(true);\r
111                         rgbButton.setSelection(false);\r
112                         type = ColorGradient.HSV;\r
113                         gradientComposite.setGradient(new ColorGradient(values,type));\r
114                 }\r
115             });\r
116             hsvButton.setText("HSV");\r
117            \r
118             viewer = new TableViewer(this,SWT.SINGLE | SWT.BORDER | SWT.FULL_SELECTION);\r
119             final Table table = viewer.getTable();\r
120             \r
121             table.setLinesVisible(true);\r
122             table.setHeaderVisible(true);\r
123             \r
124             viewer.addSelectionChangedListener(this);\r
125             viewer.addPostSelectionChangedListener(this);\r
126             \r
127             TableColumn column = new TableColumn(table,SWT.RIGHT);\r
128             column.setText("Color");\r
129             column.setWidth(60);\r
130             column.setMoveable(false);\r
131             column.setResizable(false);\r
132             column = new TableColumn(table,SWT.LEFT);\r
133             column.setText("Value");\r
134             column.setWidth(300);\r
135             column.setMoveable(false);\r
136             \r
137             viewer.setColumnProperties(new String[]{COLOR_ID,VALUE_ID});\r
138             \r
139             viewer.setLabelProvider(new TableLabelProvider());\r
140             viewer.setContentProvider(new TableContentProvider());\r
141             viewer.setInput(values);\r
142             \r
143             final ColorCellEditor colorEditor = new ColorCellEditor(table);\r
144             final TextCellEditor valueEditor = new TextCellEditor(table);\r
145             colorEditor.addListener(this);\r
146             valueEditor.addListener(this);\r
147             valueEditor.addPropertyChangeListener(this);\r
148             viewer.setCellEditors(new CellEditor[]{colorEditor,valueEditor});\r
149             \r
150             viewer.setCellModifier(new TableCellEditorModifier());    \r
151             \r
152             Composite buttonComposite = new Composite(this,SWT.NONE);\r
153 \r
154             buttonComposite.setLayout(new FillLayout(SWT.VERTICAL));\r
155             \r
156             addButton = new Button(buttonComposite,SWT.PUSH);\r
157             addButton.setText("Add new color");\r
158             addButton.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { \r
159                 public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {    \r
160                         ColorDialog dialog = new ColorDialog(ColorGradientComposite.this.getShell(), SWT.NONE);\r
161                 \r
162                 RGB rgb = dialog.open();\r
163                 if (rgb != null) {\r
164                     Color c = new Color(rgb.red,rgb.green,rgb.blue);\r
165                     Double value;\r
166                     if (values.size() == 0) {\r
167                         value = 0.0;\r
168                     } else if (values.size() == 1) {\r
169                         value = 100.0;\r
170                     } else {\r
171                         StructuredSelection selection = (StructuredSelection)viewer.getSelection();\r
172                         if (selection.size() == 1) {\r
173                                 // add new color next to the selection\r
174                                 ColorValue v = (ColorValue)selection.getFirstElement();\r
175                                 int index = values.indexOf(v);\r
176                                 if (index == values.size() -1) {\r
177                                         index--;\r
178                                 }\r
179                                 value = (values.get(index+1).getValue()-values.get(index).getValue())*0.5;\r
180                                 value += values.get(index).getValue();\r
181                         } else {\r
182                                 // add new color to largest gap\r
183                                 int index = 0;\r
184                                 double r = 0.0;\r
185                                 for (int i = 0; i < values.size() -1; i++) {\r
186                                         double v1 = values.get(i).getValue();\r
187                                         double v2 = values.get(i+1).getValue();\r
188                                         double vr = v2 -v1;\r
189                                         if (vr > r) {\r
190                                                 r=vr;\r
191                                                 index = i;\r
192                                         }\r
193                                 }\r
194                                 value = values.get(index).getValue() + r *0.5;\r
195                         }\r
196                     }\r
197                     addColor(c,value);\r
198                 }\r
199             }\r
200         });\r
201             editButton = new Button(buttonComposite,SWT.PUSH);\r
202             editButton.setText("Edit color");\r
203             editButton.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { \r
204                 public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {    \r
205                         TableItem selection[] = table.getSelection();\r
206                         if (selection.length > 0) {\r
207                                 TableItem selected = selection[0];\r
208                                 Object obj = selected.getData();\r
209                                 if (obj instanceof ColorValue) {\r
210                                         ColorDialog dialog = new ColorDialog(ColorGradientComposite.this.getShell(), SWT.NONE);\r
211                                         dialog.setRGB(getRGB(((ColorValue)obj).getColor()));\r
212                                         RGB rgb = dialog.open();\r
213                         if (rgb != null) {\r
214                                 modifyColorValueColor((ColorValue)obj,rgb);\r
215                         }\r
216                                 }                       \r
217                         }\r
218                 }\r
219         });\r
220             editButton.setEnabled(false);\r
221             removeButton = new Button(buttonComposite,SWT.PUSH);\r
222             removeButton.setText("Remove color");\r
223             removeButton.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { \r
224                 public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {    \r
225                         TableItem selection[] = table.getSelection();\r
226                         if (selection.length > 0) {\r
227                                 TableItem selected = selection[0];\r
228                                 Object o = selected.getData();\r
229                                 if (o instanceof ColorValue) {\r
230                                         Image i = images.get(o);\r
231                                         i.dispose();\r
232                                         images.remove(o);\r
233                                         values.remove(o);\r
234                                         updateWidgets();\r
235                                 }                       \r
236                         }\r
237                 }\r
238         });\r
239             removeButton.setEnabled(false);\r
240             \r
241             GridDataFactory.fillDefaults().span(1, 1).grab(true, false).align(SWT.FILL, SWT.CENTER).hint(SWT.DEFAULT, 32).applyTo(gradientComposite);\r
242             GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.CENTER).hint(SWT.DEFAULT, 100).applyTo(table);\r
243             GridDataFactory.fillDefaults().grab(false, true).align(SWT.LEFT, SWT.FILL).applyTo(typeComposite);\r
244             GridDataFactory.fillDefaults().span(1, 1).grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(buttonComposite);\r
245             \r
246             \r
247         }\r
248 \r
249         public void addColor(Color color, double value) {\r
250                 addColor(new ColorValue(color,value));\r
251         }\r
252         \r
253         public void addColor(ColorValue value) {\r
254                 values.add(value);\r
255                 Image image = ColorIconCreator.createImage(value.getColor(), ICON_WIDTH, ICON_HEIGHT, SWT.BORDER);\r
256                 images.put(value,image);\r
257                 updateWidgets();\r
258                 //viewer.refresh(true);\r
259         }\r
260         \r
261         private void updateWidgets() {\r
262                 Collections.sort(values,new ColorValueComparator());    \r
263                 gradientComposite.setGradient(new ColorGradient(values,type));\r
264                 viewer.refresh();\r
265                 \r
266         }\r
267 \r
268         public ColorGradient getGradient() {\r
269                 return new ColorGradient(values,type);\r
270         }\r
271 \r
272         public void dispose() {\r
273                 for (Image i : images.values())\r
274                         i.dispose();\r
275                 \r
276         }\r
277         \r
278         public void setGradient(ColorGradient gradient) {\r
279                 for (Image i : images.values())\r
280                         i.dispose();\r
281                 values.clear();\r
282                 images.clear();\r
283                 type = gradient.getType();\r
284                 for (ColorValue value : gradient.getColorValues())\r
285                         addColor(value);\r
286                 if (type == ColorGradient.HSV) {\r
287                         rgbButton.setSelection(false);\r
288                         hsvButton.setSelection(true);\r
289                 } else if (type == ColorGradient.RGB) {\r
290                         hsvButton.setSelection(false);\r
291                         rgbButton.setSelection(true);\r
292                 }\r
293                 \r
294         }\r
295         \r
296         private RGB getRGB(Color color) {\r
297                 RGB rgb = new RGB(color.getR(),color.getG(),color.getB());\r
298                 return rgb;\r
299         }\r
300         \r
301         private void modifyColorValueValue(ColorValue cValue, String string) {\r
302                 try {\r
303                         double d = Double.parseDouble(string);\r
304                         values.remove(cValue);\r
305                         Image image = images.get(cValue);\r
306                         images.remove(cValue);\r
307                         ColorValue newCValue = new ColorValue(cValue.getColor(),d);\r
308                         values.add(newCValue);\r
309                         images.put(newCValue,image);\r
310                         updateWidgets();\r
311                         \r
312                 } catch (NumberFormatException e) {\r
313                         return;\r
314                 }\r
315         }\r
316         \r
317         private void modifyColorValueColor(ColorValue cValue, RGB rgb) {\r
318                 values.remove(cValue);\r
319                 Image oldImage = images.get(cValue);\r
320                 oldImage.dispose();\r
321                 images.remove(cValue);\r
322                 \r
323                 Color newColor = new Color(rgb.red,rgb.green,rgb.blue);\r
324                 ColorValue newCValue = new ColorValue(newColor,cValue.getValue());\r
325                 values.add(newCValue);\r
326                 Image newImage = ColorIconCreator.createImage(newColor, ICON_WIDTH, ICON_HEIGHT, SWT.BORDER);\r
327                 images.put(newCValue,newImage);\r
328                 updateWidgets();\r
329         }\r
330         \r
331         /**\r
332          * Enables and disables "Edit color" and "Remove color" buttons depending on selected item\r
333          */\r
334         public void selectionChanged(SelectionChangedEvent event) {\r
335                 Object obj = ((IStructuredSelection)event.getSelection()).getFirstElement();\r
336                 if (obj == null) {\r
337                         editButton.setEnabled(false);\r
338                         removeButton.setEnabled(false);\r
339                 } else {\r
340                         editButton.setEnabled(true);\r
341                         removeButton.setEnabled(true);\r
342                 }\r
343         }\r
344         \r
345         /*\r
346          * FIXME :\r
347          * If item is opened for editing selectionChanged won't get null selection and\r
348          * "Edit" & "Remove" buttons are enabled when there's no valid selection\r
349          * \r
350          * There seems to be no way to get event when cellEditor is activated...\r
351          */\r
352         \r
353         public void applyEditorValue() {\r
354                 // TODO Auto-generated method stub\r
355                 editButton.setEnabled(false);\r
356                 removeButton.setEnabled(false); \r
357         }\r
358         \r
359         public void cancelEditor() {\r
360                 // TODO Auto-generated method stub\r
361                 editButton.setEnabled(false);\r
362                 removeButton.setEnabled(false); \r
363         }\r
364         \r
365         public void editorValueChanged(boolean oldValidState, boolean newValidState) {\r
366                 // TODO Auto-generated method stub\r
367                 editButton.setEnabled(false);\r
368                 removeButton.setEnabled(false); \r
369         }\r
370         \r
371         public void propertyChange(PropertyChangeEvent event) {\r
372                 editButton.setEnabled(false);\r
373                 removeButton.setEnabled(false); \r
374                 \r
375         }\r
376         /**\r
377          * @author Marko Luukkainen\r
378          *\r
379          */\r
380         private class TableLabelProvider implements ITableLabelProvider {\r
381                 private ArrayList<ILabelProviderListener> listeners = new ArrayList<ILabelProviderListener>();\r
382                                 \r
383                 /* (non-Javadoc)\r
384                  * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()\r
385                  */\r
386                 public void dispose() {\r
387                                                 \r
388                 }\r
389                 /* (non-Javadoc)\r
390                  * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int)\r
391                  */\r
392                 public Image getColumnImage(Object element, int columnIndex) {\r
393                         //System.out.println("TableLabelProvider.getColumnImage() " + element + " , " + columnIndex);\r
394                         ColorValue value = (ColorValue)element;\r
395                         if (columnIndex == 0)\r
396                                 return images.get(value);\r
397                         return null;\r
398                 }\r
399                 /* (non-Javadoc)\r
400                  * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int)\r
401                  */\r
402                 public String getColumnText(Object element, int columnIndex) {\r
403                         //System.out.println("TableLabelProvider.getColumnText() " + element + " , " + columnIndex);\r
404                         ColorValue value = (ColorValue)element;\r
405                         if (columnIndex == 1)\r
406                                 return Double.toString(value.getValue());\r
407                         return null;\r
408                 }\r
409                 /* (non-Javadoc)\r
410                  * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, java.lang.String)\r
411                  */\r
412                 public boolean isLabelProperty(Object element, String property) {\r
413                         return true;\r
414                 }\r
415                 /* (non-Javadoc)\r
416                  * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)\r
417                  */\r
418                 public void addListener(ILabelProviderListener listener) {\r
419                         if(!listeners.contains(listener))\r
420                                 listeners.add(listener);                        \r
421                 }\r
422                 /* (non-Javadoc)\r
423                  * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)\r
424                  */\r
425                 public void removeListener(ILabelProviderListener listener) {\r
426                         listeners.remove(listener);\r
427                 }\r
428                 \r
429                 \r
430         }\r
431         \r
432         /**\r
433          * @author Marko Luukkainen\r
434          *\r
435          */\r
436         private class TableContentProvider implements IStructuredContentProvider {\r
437                 public void dispose() {\r
438                         \r
439                 }\r
440                 public Object[] getElements(Object inputElement) {\r
441                         ColorValue valueArray[] = new ColorValue[values.size()];\r
442                         // values.toArray(valueArray);\r
443             // to get correct ordering (smallest last)\r
444             // we must reverse the order of the list\r
445             for (int i = 0; i < values.size(); i++) {\r
446                             valueArray[i] = values.get(values.size() - 1 -i);\r
447             }\r
448             //System.out.println("TableContentProvider.getElements() : array size " + valueArray.length);\r
449                         return valueArray;\r
450                 }\r
451                 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\r
452                         //System.out.println("TableContentProvider.inputChanged()");\r
453                         \r
454                 }\r
455         }\r
456         \r
457         /**\r
458          * @author Marko Luukkainen\r
459          *\r
460          */\r
461         private class TableCellEditorModifier implements ICellModifier {\r
462                 public boolean canModify(Object element, String property) {\r
463                         //System.out.println("TableCellEditorModifier.canModify()" + element + " , " + property);\r
464                         if (property == VALUE_ID)\r
465                                 return true;\r
466                         // this is commented out because it's hard so select the row when both rows have editors\r
467                         // now the color can be changed with "Edit Color" button\r
468                         //if (property == COLOR_ID)\r
469                         //      return true;\r
470                         return false;\r
471                 }\r
472                 public Object getValue(Object element, String property) {\r
473                         //System.out.println("TableCellEditorModifier.getValue()" + element + " , " + property);\r
474                         if (property == VALUE_ID)\r
475                                 return Double.toString(((ColorValue)element).getValue());\r
476                         if (property == COLOR_ID) \r
477                                 return getRGB(((ColorValue)element).getColor());\r
478                         return null;\r
479                         \r
480                 }\r
481                 public void modify(Object element, String property, Object value) {\r
482                         TableItem item = (TableItem)element;\r
483                         Object obj = item.getData();\r
484                         //System.out.println("TableCellEditorModifier.modify()" + element + " , " + property + " , " + value);\r
485                         if (property == VALUE_ID)\r
486                                 modifyColorValueValue((ColorValue)obj,(String)value);\r
487                         if (property == COLOR_ID)\r
488                                 modifyColorValueColor((ColorValue)obj,(RGB)value);\r
489                 }\r
490                 \r
491         }\r
492 }\r
493 \r
494         \r