/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * 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: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.utils.ui.color; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.ColorCellEditor; import org.eclipse.jface.viewers.ICellEditorListener; import org.eclipse.jface.viewers.ICellModifier; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TextCellEditor; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.ColorDialog; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; /** * Widget to create and edit color gradients * * @author Marko Luukkainen * */ public class ColorGradientComposite extends Composite implements ISelectionChangedListener, ICellEditorListener, IPropertyChangeListener{ private static int ICON_WIDTH = 36; private static int ICON_HEIGHT = 14; private static final String COLOR_ID = "Color"; private static final String VALUE_ID = "Value"; private ColorGradientCanvas gradientComposite; //private Table table; private TableViewer viewer; private Button addButton; private Button editButton; private Button removeButton; private Button rgbButton; private Button hsvButton; private int type = ColorGradient.RGB; private ArrayList values = new ArrayList(); //private ArrayList images = new ArrayList(); //private HashMap items = new HashMap(); private HashMap images = new HashMap(); public ColorGradientComposite(Composite parent, int style) { super(parent,style); FormLayout layout = new FormLayout(); this.setLayout(layout); gradientComposite = new ColorGradientCanvas(this,SWT.HORIZONTAL); Group typeComposite = new Group(this,SWT.NONE); typeComposite.setText("Color interpolation type"); typeComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); Label rgbLabel = new Label(typeComposite,SWT.NONE); rgbLabel.setText("RGB"); rgbButton = new Button(typeComposite,SWT.RADIO); rgbButton.setSelection(true); rgbButton.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } public void widgetSelected(SelectionEvent e) { rgbButton.setSelection(true); hsvButton.setSelection(false); type = ColorGradient.RGB; gradientComposite.setGradient(new ColorGradient(values,type)); } }); Label hsvLabel = new Label(typeComposite,SWT.NONE); hsvLabel.setText("HSV"); hsvButton = new Button(typeComposite,SWT.RADIO); hsvButton.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } public void widgetSelected(SelectionEvent e) { hsvButton.setSelection(true); rgbButton.setSelection(false); type = ColorGradient.HSV; gradientComposite.setGradient(new ColorGradient(values,type)); } }); viewer = new TableViewer(this,SWT.SINGLE | SWT.BORDER | SWT.FULL_SELECTION); //table = new Table(this,SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER); final Table table = viewer.getTable(); table.setLinesVisible(true); table.setHeaderVisible(true); viewer.addSelectionChangedListener(this); viewer.addPostSelectionChangedListener(this); TableColumn column = new TableColumn(table,SWT.RIGHT); column.setText("Color"); column.setWidth(40); column.setMoveable(false); column.setResizable(false); column = new TableColumn(table,SWT.LEFT); column.setText("Value"); column.setWidth(300); column.setMoveable(false); viewer.setColumnProperties(new String[]{COLOR_ID,VALUE_ID}); viewer.setLabelProvider(new TableLabelProvider()); viewer.setContentProvider(new TableContentProvider()); viewer.setInput(values); final ColorCellEditor colorEditor = new ColorCellEditor(table); final TextCellEditor valueEditor = new TextCellEditor(table); colorEditor.addListener(this); valueEditor.addListener(this); valueEditor.addPropertyChangeListener(this); viewer.setCellEditors(new CellEditor[]{colorEditor,valueEditor}); viewer.setCellModifier(new TableCellEditorModifier()); Composite buttonComposite = new Composite(this,SWT.NONE); buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); addButton = new Button(buttonComposite,SWT.PUSH); addButton.setText("Add new color"); addButton.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { ColorDialog dialog = new ColorDialog(ColorGradientComposite.this.getShell(), SWT.NONE); RGB rgb = dialog.open(); if (rgb != null) { Color c = new Color(rgb.red,rgb.green,rgb.blue); Double value; if (values.size() == 0) { value = 0.0; } else if (values.size() == 1) { value = 100.0; } else { // FIXME : insert some logic here value = 100.0 * Math.random(); } addColor(c,value); } } }); editButton = new Button(buttonComposite,SWT.PUSH); editButton.setText("Edit color"); editButton.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { TableItem selection[] = table.getSelection(); if (selection.length > 0) { TableItem selected = selection[0]; Object obj = selected.getData(); if (obj instanceof ColorValue) { ColorDialog dialog = new ColorDialog(ColorGradientComposite.this.getShell(), SWT.NONE); dialog.setRGB(getRGB(((ColorValue)obj).getColor())); RGB rgb = dialog.open(); if (rgb != null) { modifyColorValueColor((ColorValue)obj,rgb); } } } } }); editButton.setEnabled(false); removeButton = new Button(buttonComposite,SWT.PUSH); removeButton.setText("Remove color"); removeButton.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { TableItem selection[] = table.getSelection(); if (selection.length > 0) { TableItem selected = selection[0]; Object o = selected.getData(); if (o instanceof ColorValue) { Image i = images.get(o); i.dispose(); images.remove(o); values.remove(o); updateWidgets(); } } } }); removeButton.setEnabled(false); FormData gradientData = new FormData(); gradientData.top = new FormAttachment(0,0); gradientData.left = new FormAttachment(0,0); gradientData.right = new FormAttachment(100,0); gradientData.height = 40; gradientComposite.setLayoutData(gradientData); FormData typeData = new FormData(); typeData.left = new FormAttachment(0,0); typeData.right = new FormAttachment(100,0); typeData.top = new FormAttachment(gradientComposite,0,SWT.BOTTOM); typeData.height = 20; typeComposite.setLayoutData(typeData); FormData buttonData = new FormData(); buttonData.left = new FormAttachment(0,0); buttonData.right = new FormAttachment(100,0); buttonData.bottom = new FormAttachment(100,0); buttonData.height = 30; buttonComposite.setLayoutData(buttonData); FormData viewerData = new FormData(); viewerData.top = new FormAttachment(typeComposite,0,SWT.BOTTOM); viewerData.left = new FormAttachment(0,0); viewerData.right = new FormAttachment(100,0); viewerData.bottom = new FormAttachment(buttonComposite,0,SWT.TOP); table.setLayoutData(viewerData); } /* private void addColorValueToTable(ColorValue value) { TableItem item = new TableItem(table,SWT.NONE); item.setText(Double.toString(value.getValue())); Image image = ColorIconCreator.createImage(value.getColor(), 14); item.setImage(image); images.add(image); items.put(item,value); } */ /* private void sortItems() { for (Image i : images) i.dispose(); for (TableItem item : table.getItems()) if(!item.isDisposed()) item.dispose(); items.clear(); Collections.sort(values,new ColorValueComparator()); for (ColorValue value : values) { addColorValueToTable(value); } } */ public void addColor(Color color, double value) { addColor(new ColorValue(color,value)); } public void addColor(ColorValue value) { values.add(value); Image image = ColorIconCreator.createImage(value.getColor(), ICON_WIDTH, ICON_HEIGHT); images.put(value,image); updateWidgets(); //viewer.refresh(true); } private void updateWidgets() { Collections.sort(values,new ColorValueComparator()); gradientComposite.setGradient(new ColorGradient(values,type)); viewer.refresh(); } /* public void addColor(ColorValue value) { values.add(value); sortItems(); // sortItem creates new menuitems, which makes selectedItem disposed for (TableItem item : items.keySet() ) { if (items.get(item) == value) { gradientComposite.setGradient(new ColorGradient(values,type)); return; } } gradientComposite.setGradient(new ColorGradient(values,type)); } */ public ColorGradient getGradient() { return new ColorGradient(values,type); } /* public void dispose() { for (Image i : images) i.dispose(); if (!table.isDisposed()) { for (TableItem item : table.getItems()) if(!item.isDisposed()) item.dispose(); table.dispose(); } } */ public void dispose() { for (Image i : images.values()) i.dispose(); } public void setGradient(ColorGradient gradient) { for (Image i : images.values()) i.dispose(); values.clear(); images.clear(); type = gradient.getType(); for (ColorValue value : gradient.getColorValues()) addColor(value); } // private org.eclipse.swt.graphics.Color getSWTColor(Color color){ // org.eclipse.swt.graphics.Color swtColor = new org.eclipse.swt.graphics.Color(Display.getCurrent(), color.getR(), color.getG(), color.getB()); // return swtColor; // } private RGB getRGB(Color color) { RGB rgb = new RGB(color.getR(),color.getG(),color.getB()); return rgb; } private void modifyColorValueValue(ColorValue cValue, String string) { try { double d = Double.parseDouble(string); values.remove(cValue); Image image = images.get(cValue); images.remove(cValue); ColorValue newCValue = new ColorValue(cValue.getColor(),d); values.add(newCValue); images.put(newCValue,image); updateWidgets(); } catch (NumberFormatException e) { return; } } private void modifyColorValueColor(ColorValue cValue, RGB rgb) { values.remove(cValue); Image oldImage = images.get(cValue); oldImage.dispose(); images.remove(cValue); Color newColor = new Color(rgb.red,rgb.green,rgb.blue); ColorValue newCValue = new ColorValue(newColor,cValue.getValue()); values.add(newCValue); Image newImage = ColorIconCreator.createImage(newColor, ICON_WIDTH, ICON_HEIGHT); images.put(newCValue,newImage); updateWidgets(); } /** * Enables and disables "Edit color" and "Remove color" buttons depending on selected item */ public void selectionChanged(SelectionChangedEvent event) { Object obj = ((IStructuredSelection)event.getSelection()).getFirstElement(); if (obj == null) { editButton.setEnabled(false); removeButton.setEnabled(false); } else { editButton.setEnabled(true); removeButton.setEnabled(true); } } /* * FIXME : * If item is opened for editing selectionChanged won't get null selection and * "Edit" & "Remove" buttons are enabled when there's no valid selection * * There seems to be no way to get event when cellEditor is activated... */ public void applyEditorValue() { // TODO Auto-generated method stub editButton.setEnabled(false); removeButton.setEnabled(false); } public void cancelEditor() { // TODO Auto-generated method stub editButton.setEnabled(false); removeButton.setEnabled(false); } public void editorValueChanged(boolean oldValidState, boolean newValidState) { // TODO Auto-generated method stub editButton.setEnabled(false); removeButton.setEnabled(false); } public void propertyChange(PropertyChangeEvent event) { editButton.setEnabled(false); removeButton.setEnabled(false); } /** * @author Marko Luukkainen * */ private class TableLabelProvider implements ITableLabelProvider { private ArrayList listeners = new ArrayList(); /* (non-Javadoc) * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose() */ public void dispose() { } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int) */ public Image getColumnImage(Object element, int columnIndex) { //System.out.println("TableLabelProvider.getColumnImage() " + element + " , " + columnIndex); ColorValue value = (ColorValue)element; if (columnIndex == 0) return images.get(value); return null; } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int) */ public String getColumnText(Object element, int columnIndex) { //System.out.println("TableLabelProvider.getColumnText() " + element + " , " + columnIndex); ColorValue value = (ColorValue)element; if (columnIndex == 1) return Double.toString(value.getValue()); return null; } /* (non-Javadoc) * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, java.lang.String) */ public boolean isLabelProperty(Object element, String property) { return true; } /* (non-Javadoc) * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener) */ public void addListener(ILabelProviderListener listener) { if(!listeners.contains(listener)) listeners.add(listener); } /* (non-Javadoc) * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener) */ public void removeListener(ILabelProviderListener listener) { listeners.remove(listener); } } /** * @author Marko Luukkainen * */ private class TableContentProvider implements IStructuredContentProvider { public void dispose() { } public Object[] getElements(Object inputElement) { ColorValue valueArray[] = new ColorValue[values.size()]; // values.toArray(valueArray); // to get correct ordering (smallest last) // we must reverse the order of the list for (int i = 0; i < values.size(); i++) { valueArray[i] = values.get(values.size() - 1 -i); } //System.out.println("TableContentProvider.getElements() : array size " + valueArray.length); return valueArray; } public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { //System.out.println("TableContentProvider.inputChanged()"); } } /** * @author Marko Luukkainen * */ private class TableCellEditorModifier implements ICellModifier { public boolean canModify(Object element, String property) { //System.out.println("TableCellEditorModifier.canModify()" + element + " , " + property); if (property == VALUE_ID) return true; // this is commented out because it's hard so select the row when both rows have editors // now the color can be changed with "Edit Color" button //if (property == COLOR_ID) // return true; return false; } public Object getValue(Object element, String property) { //System.out.println("TableCellEditorModifier.getValue()" + element + " , " + property); if (property == VALUE_ID) return Double.toString(((ColorValue)element).getValue()); if (property == COLOR_ID) return getRGB(((ColorValue)element).getColor()); return null; } public void modify(Object element, String property, Object value) { TableItem item = (TableItem)element; Object obj = item.getData(); //System.out.println("TableCellEditorModifier.modify()" + element + " , " + property + " , " + value); if (property == VALUE_ID) modifyColorValueValue((ColorValue)obj,(String)value); if (property == COLOR_ID) modifyColorValueColor((ColorValue)obj,(RGB)value); } } }